[Закрыть]
 
popoff.donetsk.ua
Всем кажется, что строй - это такая реальность. На самом деле, необходимость находиться в строю - это иллюзия. Настоящая реальность состоит в том, что можно выйти из строя и отправиться своей дорогой.
Начало | Новости | Статьи | Форум | Опросы | Карта сайта | Обо мне
popoff.donetsk.ua - Клуппы Yato - Программирование - Модули - a - date
Я это делаю
Персональное меню
Голосование
Клуппы Yato Постоянный адрес этого вопроса
Ваш возраст (не обязательно):

Введите целое число от 3 до 99.
Почему? (не обязательно):
Другие вопросы
Поиск по сайту
Реклама
Гинеколог, стоматолог, психотерапевт в Донецке
Статистика

date

Постоянный адрес статьи
Существует несчетное множество библиотек для работы с датами. Есть встроенные в php функции; работа с датами поддерживается в MySQL. Для чего же я написал еще одну?
Исходный текст библиотеки для работы с датами

Для чего нужна эта библиотека

Постоянный адрес статьи

Существует несчетное множество библиотек для работы с датами. Есть встроенные в php функции; работа с датами поддерживается в MySQL. Для чего же я написал еще одну?

  1. <p> В большом проекте все должно быть стандартизовано. В том числе и работа с датами. Если у нас есть выбор - работать ли с датами при помощи встроенных функций php, при помощи некоторых расширений или при помощи встроенных функций MySQL, то это означает, что в проекте нет стандарта на работу с датами. А в таком случае любое изменение (например, раньше не учитывалось локальное положение пользователя, а теперь учитывается) потребует пересмотра значительной части проекта. При использовании одной библиотеки потребуется пересмотреть только эту библиотеку. </p><p> Заявления о том, что все нужно предусмотреть заранее не принимаются в связи с невозможностью выполнения такого требования. </p><p> При использовании этой библиотеки у нас всегда есть ВСЕ необходимые нам функции, которые работают именно так, как мы этого хотим. Этот набор функций не зависит от того, какие другие библиотеки мы используем. </p><p> Многие функции моей библиотеки используют встроенные функции. Как только окажется, что встроенные функции работают не так, как мне это нужно (например, налагают ограничение на диапазон дат), мне нужно будет ТОЛЬКО изменить функцию внутри моей библиотеки. Раньше я должен был бы искать по всему своему проекту, «а где это у меня там была работа с датами такая, что существующие ограничения там недопустимы». </p><p> Если какие-то стандартные функции не выполняют над датами те операции, которые нам нужны, мы просто добавляем в нашу библиотеку функцию, которая будет делать то, что нам нужно. </p>
  2. <p> Стандартизуется не только набор функций обработки дат, но и внутреннее представление даты. С использованием этой библиотеки даты всегда представляются в виде массива, содержащего в себе год, месяц, день, часы, минуты и секунды. В моем случае массив - это наиболее подходящий способ представления даты в php. Все остальные способы так или иначе налагают некоторые ограничения. </p><p> Почему не строка, как это делается в MySQL? Потому что выбрать из этой строки, например, номер дня в php несколько сложнее, чем выбрать из массива элемент с индексом 1. </p><p> Почему не встроенный вариант - unix timestamp? У этого способа есть известное преимущество - легко посчитать расстояние между двумя временными отметками. Но для определения номера дня потребуется дополнительный вызов функции, которая вернет массив с соответствующими данными, а потом из этого массива выбирается нужное нам значение. При использовании такого способа мы не только добавляем вызов функции, но и, самое важное, зависим от того, какой массив возвращает эта функция. К тому же при использовании unix timestamp допустимый диапазон дат значительно ограничен. Поэтому нам это не подходит. </p><p> В целом можно вообще запретить доступ к элементам этого массива и обращаться к данным только через специальные функции. В таком случае дату можно рассматривать как некоторый объект. Почему я использую именно массив, а не объекты? Так сложилось исторически. В моем проекте нигде не используются объекты. </p><p> Зачем вообще нужно стандартизировать внутреннее представление даты? Я думаю, в этом вопросе ключевым является вопрос «зачем вообще нужно стандартизировать», а «внутреннее представление даты» - это уже как вариант того, что конкретно мы стандартизируем. Я поразмыслю над вопросом «зачем нужна стандартизация в программировании» и, возможно, как-нибудь напишу статью на эту тему. А пока я ее не написал, Вы можете поискать статью на эту тему у других авторов. </p>

Эта библиотека не должна использоваться как расширение к существующим библиотекам работы с датами. Если в этой библиотеке есть функции, которые делают что-то, что не делается при помощи стандартных функций, то это лишь незначительный бонус, предоставляемый это библиотекой.

Эта библиотека должна использоваться как средство стандартизации работы с датами в Вашем проекте.

Исходный текст

Постоянный адрес статьи
<?php
// libs/date/date.php
// (c) Yuri Popoff, Mar 2002, popoff.donetsk.ua
// Библиотека функций для работы с датами

// Правила именования функций:
// date_x_y - конвертирует дату из формата x в формат y.
// x - формат аргумента (что подается на вход?)
// y - формат результата (что получается на выходе?)
// в качестве x и y может быть (часто встречаемые значения):
// - a (array) - массив из шести элементов, в котором содержится
//   год, месяц, день, часы, минуты, секунды,
//   например, array(2005,12,31,12,54,44) соответствует 31 янв 2005 12:54:44.
// - dc (day count) - целое число, которое обозначает количество дней,
//   прошедшее после 01.01.0001
// - mysql - строка, содержащая дату в формате, используемом в MySQL,
//   например 2005-12-1 12:54:44
// - unix - целое число, обозначающее количество секунд, прошедшее
//   после 01.01.1970 00:00:00. (unix timestamp)
// - ts - строка, содержащая временную отметку (timestamp) в формате,
//   используемом в MySQL, например 20051201125444
// например, функция date_unix_a конвертирует дату из формата unix timestamp
//   (целое число) в массив (год, месяц, день, часы, минуты, секунды)

function date_a_add_day($a)
// добавить день к дате
{
  
$dm=array(31,28,31,30,31,30,31,31,30,31,30,31);
  if(
$a[1]==2&&date_year_leap($a[0])) $dm[1]=29;
  if(
$a[2]>=$dm[$a[1]-1])
  {
    
$a[2]=1;
    return
date_a_add_month($a);
  }
  else
  {
    
$a[2]++;
  }
  return
$a;
}

function
date_a_add_hour($a)
// добавить час к дате
{
  if(
$a[3]>=23)
  {
    
$a[3]=0;
    return
date_a_add_day($a);
  }
  else
  {
    
$a[3]++;
  }
  return
$a;
}

function
date_a_add_month($a)
// добавить месяц к дате
{
  if(
$a[1]>=12)
  {
    
$a[1]=1;
    return
date_a_add_year($a);
  }
  else
  {
    
$a[1]++;
  }
  return
$a;
}

function
date_a_add_year($a)
// добавить год к дате
{
  
$a[0]++;
  if(
$a[1]==2&&$a[2]==29) $a[2]=28;
  return
$a;
}

function
date_a_age($a)
// посчитать возраст человека на текущий момент
{
  
$dc1=date_a_dc($a);
  
$b=getdate(time());
  
$dc2=date_a_dc(array($b['year'],$b{'mon'},$b{'mday'},0,0,0));
  
$dc=$dc2-$dc1;
  
$c=date_dc_a($dc);
  return
$c[0]-1;
}

function
date_a_compare($a1,$a2)
// сравнить две даты. возвращаемые значения:
// -1 - a1<a2
//  0 - a1=a2
//  1 - a1>a2
{
  for(
$i=0;$i<6;$i++)
    if(
$a1[$i]<$a2[$i])
      return -
1;
    else
      if(
$a1[$i]>$a2[$i])
        return
1;

  return
0;
}

function
date_a_dc($a)
{
  
$y=$a[0]-1;
  
$dc=$y*365+floor($y/4)-floor($y/100)+floor($y/400);
  
$sm=array(0,31,59,90,120,151,181,212,243,273,304,334);
  
$dc+=$sm[$a[1]-1];
  if(
$a[1]>2&&date_year_leap($a[0])) $dc++;
  
$dc+=$a[2];
  return
$dc;
}

function
date_a_mysql($a)
{
  return
$a{0}.'-'.$a{1}.'-'.$a{2}.' '.$a[3].':'.$a[4].':'.$a[5];
}

function
date_a_normalize($a)
// нормализовать дату.
// если $a содержит в себе правильную (допустимую) дату, то
//   возвращает $a без изменений
// иначе изменяет $a так, что бы дата была допустимой
// $a может содержать в себе любое неправильное значение,
//   на выходе всегда будет правильная дата
{
  if(!
is_array($a)) $a=array();
  
$a=array_values($a);
  while(
count($a)<6)
    
$a[]=0;
  if(!
is_numeric($a[0])||$a[0]<=0) $a[0]=1;
  if(
$a[0]>9999) $a[0]=9999;
  if(!
is_numeric($a[1])||$a[1]<1) $a[1]=1;
  if(
$a[1]>12) $a[1]=12;
  
$dm=array(31,28,31,30,31,30,31,31,30,31,30,31);
  if(
date_year_leap($a[0])) $dm[1]++;
  if(!
is_numeric($a[2])||$a[2]<1) $a[2]=1;
  if(
$a[2]>$dm{$a[1]-1}) $a[2]=$dm[$a[1]-1];
  if(!
is_numeric($a[3])||$a[3]<=0) $a[3]=0;
  if(
$a[3]>23) $a[3]=23;
  if(!
is_numeric($a[4])||$a[4]<=0) $a[4]=0;
  if(
$a[4]>59) $a[3]=59;
  if(!
is_numeric($a[5])||$a[5]<=0) $a[5]=0;
  if(
$a[5]>59) $a[5]=59;
  return
$a;
}

function
date_a_unix($a)
{
  return
mktime($a[3],$a[4],$a[5],$a[1],$a[2],$a[0]);
}

function
date_a_valid($a)
// проверяет, является ли дата правильной. возвращаемые значения:
// true - дата является правильной
// false - дата не правильная
{
  if(!
is_array($a)||count($a)!=6) return false;
  if(!isset(
$a[0])) return false;
  if(!isset(
$a[1])) return false;
  if(!isset(
$a[2])) return false;
  if(!isset(
$a[3])||!is_numeric($a[3])||$a[3]<0||$a[3]>23) return false;
  if(!isset(
$a[4])||!is_numeric($a[4])||$a[4]<0||$a[4]>59) return false;
  if(!isset(
$a[5])||!is_numeric($a[5])||$a[5]<0||$a[5]>59) return false;
  if(!
date_valid($a[0],$a[1],$a[2])) return false;
  return
true;
}

function
date_a_zero($a)
// проверяет, является ли дата нулевой. возвращаемые значения:
// true - дата является нулевой (0000-00-00 00:00:00)
// false - дата не нулевая
{
  return
    empty(
$a[0])&&
    empty(
$a[1])&&
    empty(
$a[2])&&
    empty(
$a[3])&&
    empty(
$a[4])&&
    empty(
$a[5]);
}

function
date_dc_a($dc)
{
  if(!
is_numeric($dc)||$dc<1) $dc=1;
  if(
$dc>3652059) $dc=3652059;
  
$days=$dc+306;
  
$century=floor(( 4 * $days -  1) /  146097);
  
$days   =floor (4 * $days - 1 - 146097 * $century);
  
$day    =floor($days /  4);

  
$year   =floor(( 4 * $day +  3) /  1461);
  
$day    =floor(4 * $day +  3 -  1461 * $year);
  
$day    =floor(($day +  4) /  4);

  
$month  =floor(( 5 * $day -  3) /  153);
  
$day    =floor(5 * $day -  3 -  153 * $month);
  
$day    =floor(($day +  5) /  5);

  if(
$month < 10)
    
$month +=3;
  else
  {
    
$month -=9;
    if(
$year++ == 99)
    {
      
$year = 0;
      
$century++;
    }
  }
  return array(
    
$century*100+$year,
    
$month,
    
$day,
    
0,0,0);
}

function
date_dc_week($dc)
// определяет номер дня недели. 1 - понедельник, 7 - воскресенье
{
  return (
$dc-1)%7+1;
}

function
date_mysql_a($mysql)
{
  
$a=preg_split(«/[^0-9]+/,$mysql.' 0 0 0 0 0 0',6);
  
$a{0}+=0;
  
$a{1}+=0;
  
$a{2}+=0;
  
$a{3}+=0;
  
$a{4}+=0;
  
$a{5}+=0;
  return
$a;
}

function
date_mysql_age($mysql)
// определяет возраст человека на текущий момент
{
  return
date_a_age(date_mysql_a($mysql));
}

function
date_mysql_ts($mysql)
{
  
$s='-'.preg_replace(/[^0-9]+/,'--',$mysql).'-';
  
$s=preg_replace(/-([0-9])-/»,'0\\1',$s);
  
$s=str_replace('-','',$s);
  return
$s;
}

function
date_mysql_unix($mysql)
{
  return
date_a_unix(date_mysql_a($mysql));
}

function
date_mysql_valid($mysql)
// проверяет, является ли дата правильной. возвращаемые значения:
// true - дата является правильной
// false - дата не правильная
{
  return
date_a_valid(date_mysql_a($mysql));
}

function
date_mysql_zero($mysql)
// проверяет, является ли дата нулевой. возвращаемые значения:
// true - дата является нулевой (0000-00-00 00:00:00)
// false - дата не нулевая
{
  return
date_a_zero(date_mysql_a($mysql));
}

function
date_is_valid_a($a)
{
  return
    !empty(
$a)&&
    
is_array($a)&&
    
count($a)>=3&&
    
date_valid($a{0},$a{1},$a{2});
}

function
date_unix_a($u)
{
  
$a=getdate($u);
  return
    array(
      
$a['year'],
      
$a['mon'],
      
$a['mday'],
      
$a['hours'],
      
$a['minutes'],
      
$a['seconds']);
}

function
date_unix_mysql($unix)
{
  return
date(Y-n-j G:i:s,$unix);
}

function
date_unix_ts($unix)
{
  return
date(YnjGis,$unix);
}

function
date_valid($y,$m,$d)
// проверяет, является ли дата правильной. возвращаемые значения:
// true - дата является правильной
// false - дата не правильная
{
  if(!
is_numeric($y)||!is_numeric($m)||!is_numeric($d)) return false;
  if(
$y<=0||$y>9999) return false;
  if(
$m<1||$m>12) return false;
  
$dm=array(31,28,31,30,31,30,31,31,30,31,30,31);
  if(
date_year_leap($y)) $dm{1}++;
  if(
$d<1||$d>$dm{$m-1}) return false;
  return
true;
}

function
date_year_leap($year)
// проверяет, является ли год високосным. возвращаемые значения:
// true - год является високосным
// false - год не является високосным
{
  return (
$year%4==0)&&($year%100!=0)||($year%400==0);
}

?>

Последняя модификация: 10.11.05 14:21

Обсуждение статьи в форуме

22.08.05 15:21 Screamer

У меня такое замечание. В этой библиотеке, в данной реализации, очень мало вызовов стандартных функций, все алгоритмы реализованы самостоятельно. У меня вопрос - что выполняется быстрее, один вызов пхп-функции, или два вызова встроенных функций (которые написаны на С и откомпилены)? Я поленился и не проверил профайлером, что будет выполняться быстрее, но, следуя логике, стоит отдавать предпочтение встроенным функциям. Например, можно пользоваться функцией unixtojd(), хоть ее может и не быть откомпиленной на хостинге, но можно ее подстраховать своим вариантом, а не полностью заменять ее.
А насчет стандартизации я целиком согласен, полезно

22.08.05 18:25 popoff

В целом согласен. Не хочешь доработать? :)

~~~~~ 22 Авг 2005, 18:26 ~~~~~

А так же провести эксперименты по сравнению скорости работы и описать их :)

Просмотреть все комментарии в режиме форума. Всего комментариев: 2