как сделать навигацию по датам?

Рейтинг: 1Ответов: 1Опубликовано: 30.03.2023

Как сделать навигацию, чтобы выбирая дату из выпадающих списков поля ввода и кнопок (- + 1) получить день недели на любую произвольную дату?

var selDay = document.getElementById('c_day');
var selDate = document.getElementById('c_date');
var selMonth = document.getElementById('c_month');
var inpYear = document.getElementById("c_year");
var selEra = document.getElementById("c_era");

var days = [
  "Воскресенье", "Понедельник", "Вторник",
  "Среда", "Четверг", "Пятница", "Суббота"
];

var months = [
  "января", "февраля", "марта", "апреля",
  "мая", "июня", "июля", "августа",
  "сентября", "октября", "ноября", "декабря"
];

var eras = [
  ["до н. э.", "-"],
  ["н. э.", "+"]
];

function getDaysMonth(d) {
  return 34 - new Date(d.getFullYear(), d.getMonth(), 34).getDate();
}

getDaysMonth(new Date());

var date = new Date();

var daysMonth = getDaysMonth(date);

for (var i = 0; i < daysMonth; i++) {
  var opt = selDate.appendChild(new Option(i + 1, i));
  if (i + 1 === date.getDate()) opt.selected = true;
}

for (var i = 0; i < months.length; i++) { // месяц
  var option = new Option(months[i], i);
  if (i === date.getMonth()) option.selected = true;
  selMonth.appendChild(option);
}

selDay.appendChild(new Option(days[date.getDay()])).selected = true; // день недели

inpYear.value = date.getFullYear();

inpYear.addEventListener('input', function() {
  var val = this.value.replace(/\D+/g, '');
  this.value = val.length > 6 ? val.slice(0, 6) : val;
});

for (var i = 0; i < eras.length; i++) {
  var opt = selEra.appendChild(new Option(eras[i][0], eras[i][1]));
  if (eras[i][0] === "н. э.") opt.selected = true;
}
div {
  white-space: nowrap;
}

a,
select,
input,
textarea,
button {
  outline: none;
}

select,
input,
button {
  background-color: #fff;
  color: #000;
  font: 20px serif;
  border: 1px solid #999;
  border-radius: 5px;
}

input#c_year {
  width: 92px;
  text-align: center;
  padding: 3px;
  display: inline-block; // не все браузеры применяют свойство text-align: center; к полю ввода
}

.cont {
  display: inline-flex;
  justify-content: center;
  align-content: center;
  width: auto;
  height: 40px;
}

.cont_lr {
  padding: 0;
  margin: 0;
  flex: 1 1 auto;
  align-self: stretch;
  display: inline-flex;
  flex-flow: column nowrap;
  justify-content: center;
  align-content: center;
}

.m_p {
  font: 12px/8px serif;
  padding: 3px;
  margin: 0;
  flex: 1 1 auto;
  align-self: stretch;
}
<div>
  <select id="c_day"></select><br>
  <span class="cont">
    <select id="c_date" class="cont"></select>
    <span class="cont_lr">
    <button id="munus_date" class="m_p">-</button>
    <button id="plus_date" class="m_p">+</button>
    </span>
  </span>
  <span class="cont">
    <select id="c_month" class="cont"></select>
    <span class="cont_lr">
    <button id="munus_month" class="m_p">-</button>
    <button id="plus_month" class="m_p">+</button>
    </span>
  </span>
  <span class="cont">
    <input type="text" id="c_year" class="cont"></select>
    <span class="cont_lr">
    <button id="munus_year" class="m_p">-</button>
    <button id="plus_year" class="m_p">+</button>
  </span>
  <span class="cont">
    <select id="c_era" class="cont"></select><br>
    <span class="cont_lr">
    <button id="munus_era" class="m_p">-</button>
    <button id="plus_era" class="m_p">+</button>
    </span>
  </span>
  <button id="today" style="display: none;">сегодня</button>
</div>

Ответы

▲ 0

В конкретном случае Вам вероятно достаточно будет воспользоваться методом toLocaleDateString() для вывода дня недели. Я воспользовался похожим онлайн калькулятором чтобы проверить дни. Минус этого подхода, то что не понятно как вывести 1-ый год нашей эры и некоторые другие годы.

// возвращает массив аргументов и дату с днем недели
function xDate(...args){
  const options = { weekday: 'long', year: 'numeric',  month: 'long', day: 'numeric'};
  return [args, new Date(...args).toLocaleDateString('ru-ru', options)]
}

const dates = [
  xDate(),            // текущая дата
  xDate(-1 , 0 , 1),  // 1 января 2г
  xDate(0 , 0 , 1),   // 1 января 1900г
  xDate(1401, 0, 1),  // 1 января 1401 н.э.
  xDate(-1400, 0, 1), // 1 января 1401 до н.э.
]

for (const date of dates){
  console.log(date[0].join(', ').padEnd(15, ' '), date[1]);
}

Но вообще многие годы повторяются один в один (всего их 14):

  • есть 7 високосных лет начинающихся сооответсвенно с (ПН, ВТ, СР, ЧТ, ПТ, СБ, ВС)
  • есть 7 не високосных лет начинающихся сооответсвенно с (ПН, ВТ, СР, ЧТ, ПТ, СБ, ВС)

Таким образом зная какие годы похожи можно считать дни недели по одним годам получая их и для других. Например не високосные годы начинающиеся с понедельника чередуются с разницей то в 11 то в 6 лет, закономерность есть но ее нужно увидеть тогда можно создать формулу для вычисления.

1906 + 11 = 1917; 1917 + 6  = 1923; 1923 + 11 = 1934
1934 + 11 = 1945 и т.д.

Приведу список похожих не високосных лет (то же самое и для других дней недели)

  понедельник, 1 января 1906г. 1917г. 1923г. 1934г. 1945г. ...

Вот список високосных лет можно заметить что между похожими разница 28 лет (я не проверял все, может есть исключения, но думаю там тоже есть закономерность)

понедельник, 1 января 1912г. 1940г. 1968г. 1996г.
вторник, 1 января 1924г. 1952г. 1980г. ...

И на последок, можно еще высчитывать сколько дней прошло до даты с начала года, и сколько лет было до даты (н.э) потом нужно будет посчитать сколько было високосных лет за этот период, и прибавить за каждый год по одному дню (29 февраля) далее имея число дней, можно поделить их нацело на 7 и таким образом получить день недели для пятницы будет 5 для понедельника 1 для воскресения 0. Например для 31 марта 2023 года:

((90 + (2022 * 365) + 490) % 7 ) === 5 // пятница
  • 90 дней с начала года (31 + 28 + 31 = 90)
  • 2022 года разница между 1-м годом (2023 - 1 = 2022)
  • 365 дней в каждом году (без 29 февраля — подсчитывается отдельно)
  • 490 високосных лет (с 29 февраля)

Формула для определения високосный год или нет может быть такой:

function isLeapYear(year) {
  return ((year % 4 == 0 && year % 100 != 0) || year % 400 == 0) 
}

Т.е. если год либо делится нацело на 4, но не на 100 или делится нацело на 400, тогда он високосный.

Я постарался дать достаточно данных чтобы Вы могли продолжить исследования самостоятельно. Теперь Вы знаете как вывести день недели, и как определить високосный год или нет. Так же что есть повторяющиеся годы которые чередуются с определенной закономерностью. Надеюсь, мой ответ окажется Вам полезным.

let value = 1999
const [text, date, plus, minus] 
  = document.querySelectorAll('p, button')
plus.onclick = function(){
  text.textContent = value
  date.textContent =  new Date(value, 0, 1); 
}
minus.onclick = () => {
  text.textContent = '-'+`${value}`.padStart(6, '0')
  date.textContent =  new Date(text.textContent) 
}
<p>1999</p><p></p>
<button>+</button>
<button>-</button>

ДОПОЛНЕНИЕ

Как использовать выбранные значения

Чтобы взять данные с селектов для числа месяца, месяца, и поля ввода, чтобы получить дату, нужно обратиться к каждому из этих элементов и взять value например так:

const month = selMonth.value //мы получим значение от 0 до 11 в зависимости от месяца.
const year = selMonth.value //мы получим значение от 0 до 11 в зависимости от месяца.

const date = selDate.value;   // [1-31]
const month = selMonth.value; // [0-11]
const year = +inpYear.value;  // у инпута лучше использовать type="number"
const era = selEra;  // ['-', '+']

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

const yearByEra = era === '+' ? year : parseInt(year) - 1
const padStartLenght = Math.abs(yearByEra) < 1000 && era === '-' ? 4 : 6

const yearPadded = era + `${yearByEra}`.padStart(padStartLenght, '0')
// расчет           +/-        15           0000 (ведущие нули)      => "+000015"

new Date(yearPadded, month, date)   

Что касается дней то они должны быть в диапазоне от 1.

События на кнопках

В select мы должны присвоить по нажатию на кнопку либо предыдущую либо следующую опцию (по-значению) если эти опции есть. В input просто увеличить уменьшить значение.

Так как значения идут подрят мы можем менять их например так:

selDate.value = Number(selDate.value) + 1 // или - 1
selMonth.value = Number(selMonth.value) + 1 // или - 1

Для этого на кнопки мы должны добавить события по клику, обычно это делается так:

const munusDateBtn = document.getElementById('munus_date') // minus 
const plusDateBtn = document.getElementById('plus_date')

munusDateBtn.addEventListener('click', function(){
    // обязательно проверяем что значение будет не ниже 0
    selDate.value = Number(selDate.value) - 1
}, false)

munusDateBtn.addEventListener('click', function(){
    // обязательно проверяем что значение не будет больше 31
    selDate.value = Number(selDate.value) + 1
}, false)

// 14 год ???
const month = 0
const date = 1
console.log(new Date (0014, month, date))
console.log(new Date ("0014", month, date))
//или в рассширенноом формате 
console.log(new Date (+000014, month, date))
console.log(new Date ("+000014", month, date))