БлогNot. 30 февраля или логичный календарь :)

30 февраля или логичный календарь :)

Мне нравятся реформаторы календаря. Наряду с толкованием Апокалипсиса и верой в злокозненных пришельцев (православный вариант - бесов, либеральный - агентов спецслужб), стремление реформировать календарь - третий верный индикатор той весёлой шизофрении, что делает жизнь в обывательском болоте приемлемой (в СССР повышенная креативность отчего-то именовалась вялотекущей шизофренией).

Так вот, как раз намедни был разговор на тему с одним чудаком. Почему из нескольких возможных вариантов распределения количества дней по месяцам мы выбрали явно не самый удачный - 7 месяцев по 31 дню, 4 - по 30 и один - 28 или 29.

По-моему, в блоге соответствующее диофантово уравнение уже решалось. Наш обычный год - пятое решение в списке, а его "логичный" - второе. Мне лично симпатичен и девятый вариант с 12 "лунными" месяцами по 28 дней и 13-м из 29 дней.

Правда, нарисовать такой год изменённым скриптом календаря не получится, потому что вывод скрипта зависит от результата, возвращаемого функцией date('w').

Быстрее будет реализовать на PHP банальную формулу Зеллера и написать соответствующее обрамление. Для простоты - без класса и всегда с выводом "вертикального" календаря на текущий год из 3 строк и 4 столбцов.

Предполагается, что год всегда начинается с 1 января и состоит из 12 месяцев (отчего-то, количество месяцев никогда не пытаются "оптимизировать", хотя по мне, хватило бы семи :) Также есть некий месяц, куда добавляется дополнительный день по правилам григорианского календаря. Ведь последний довольно точен, а погрешность в сутки, которую он накопит примерно за 10000 лет, легко предотвращается секундами координации, используемыми уже 45 лет.

В общем, представьте - в январе всегда 31 день, в феврале - 30, в марте - снова 31 и так до ноября, в котором будет 31. Скучный декабрь в ожидании Нового года имеет 29 дней в обычный год и 30 в високосный.

Изменив массив $dayscount и переменную $leapmonth в функции draw можно попробовать и другие варианты 12-месячного года, а "безумный календарь" на текущий год будет выглядеть в браузере вот так:

"логичный календарь"-2016
"логичный календарь"-2016

Ну и полный исходник шыдевра, конечно (на момент написания и без обрамляющих тегов HTML):

<?php
 function getweekday($d,$m,$year) { //день недели по формуле Зеллера для даты ДД.ММ.ГГГГ
  if ($m<3) { $m+=12; $year--; }
  $c=floor($year/100);
  $y=$year%100;
  $wd=($d+floor(13*($m+1)/5)+$y+floor($y/4)+floor($c/4)-2*$c)%7; //0..6=Сб..Пт
  if ($wd<2) $wd+=6; else $wd--; //1..7=Пн..Вс
  return $wd;
 }

 function leapyear ($y) { //true, если год високосный
  return ($y%4==0) and ($y%100!=0) or ($y%400==0); 
 }

 function daycolor ($d,$m,$year,$wd) { 
  //red - выходной или праздник, иначе black
  //праздники - только ДД.ММ, переносы выходных не учитываются
  $holidays = array (
   array (1,1), array (7,1), array (23,2), 
   array (8,3), array (1,5), array (9,5),
   array (12,6),
   array (4,11)
  );
  if ($wd>5) return 'red';
  for ($i=0; $i<count($holidays); $i++) if ($d==$holidays[$i][0] and $m==$holidays[$i][1]) return 'red';
  return 'black';
 }

 function draw($year) { //вывод календаря на год $year
  $months=array("Январь","Февраль","Март","Апрель","Май","Июнь",
   "Июль","Август","Сентябрь","Октябрь","Ноябрь","Декабрь"); //Названия месяцев
  $days=array("Пн","Вт","Ср","Чт","Пт","Сб","Вс"); //Названия дней недели
  $dayscount=array("31","30","31","30","31","30", 
   "31","30","31","30","31","29"); //Число дней в месяцах
  $leapmonth=12; //Номер "високосного" месяца, к которому добавляется 366-й день
  $text = '<div align="center"><b>'.$year.'</b></div>'."\n";
  $text .= '<table align="center" border="0" cellpadding="6" cellspacing="0">'."\n";
  $wd = getweekday(1,1,$year);
  for ($r=1; $r<=3; $r++) {
   $text .= '<tr>'."\n";
   for ($c=1; $c<=4; $c++) {
    $text .= '<td>'."\n";
    $m = ($r-1)*4+$c;
    $text .= '<div align="center">'.$months[$m-1].'</div>'."\n";
    $d=1;
    $upd = $dayscount[$m-1];
    if (leapyear($year) and $m==$leapmonth) $upd++;
    $text .= '<table align="center" border="0" cellpadding="3" cellspacing="0">'."\n";
    $cal = array ();
    for ($rr=1; $rr<=7; $rr++) 
     $cal[$rr] = array (2=>'&nbsp;',3=>'&nbsp;',4=>'&nbsp;',5=>'&nbsp;',6=>'&nbsp;',7=>'&nbsp;');
    for ($cc=2; $cc<=7; $cc++) {
     for ($rr=1; $rr<=7; $rr++) {
      if ($cc==2 and $rr!=$wd) continue;
      else if ($d<=$upd) {
       $color = daycolor ($d,$m,$year,$wd);
       $cal[$rr][$cc] = '<font color="'.$color.'">'.($d++).'</font>';
       $wd++;
       if ($wd>7) $wd=1;
      }
     }
    }
    for ($rr=1; $rr<=7; $rr++) {
     $text .= '<tr>'."\n";
     for ($cc=1; $cc<=7; $cc++) {
      $text .= '<td width="15%" align="right" nowrap>'."\n";
      if ($cc==1) $text .= ($rr<6?'':'<font color="red">').$days[$rr-1].($rr<6?'':'</font>')."\n";
      else $text .= $cal[$rr][$cc]."\n";
      $text .= '</td>'."\n";
     }
     $text .= '</tr>'."\n";
    }
    $text .= '</table>'."\n";
    $text .= '</td>'."\n";
   }
   $text .= '</tr>'."\n";
  }
  $text .= '</table>'."\n";
  return $text;
 }

 echo draw (date("Y")); //вызов для текущего года
?>

Список праздников, которые всегда красные, задаётся в функции daycolor. Можно впечатать "сумасшедший календарь" на плакат и разыграть подарком невнимательного знакомого.

 Этот скрипт в работе онлайн

20.02.2016, 22:57 [7298 просмотров]


теги: дата php

К этой статье пока нет комментариев, Ваш будет первым