PHP strtotime без високосных лет

Что касается этой темы, я разработал частичный решение:

function strtosecs($time,$now=null){
    static $LEAPDIFF=86400;
    $time=strtotime($time,$now);
    return $time-(round((date('Y',$time)-1968)/4)*$LEAPDIFF);
}

Предполагается, что функция получает количество секунд, заданных строкой, без проверки високосных лет.

Он делает это, вычисляя количество високосных лет 1970 [(year-1986)/4], умножая его на разницу в секундах между високосным и обычным годом (что, в конце концов, это просто количество секунд в день).

Наконец, я просто удаляю все эти лишние секунды високосного года из вычисляемого времени. Вот несколько примеров входов/выходов:

// test code
echo strtosecs('+20 years',0).'=>'.(strtosecs('+20 years',0)/31536000);
echo strtosecs('+1 years',0).'=>'.(strtosecs('+1 years',0)/31536000);

// test output
630676800 => 19.998630136986
31471200  => 0.99794520547945

Вы, наверное, спросите, почему я делаю деление на выходе? Это проверить это; 31536000 — это количество секунд в году, так что 19,99... должно быть 20, а 0,99... должно быть 1. Конечно, я мог бы округлить все это и получить «правильный» ответ, но меня беспокоит неточности.

Edit1: Поскольку это не кажется очевидным, моя проблема связана с неопытностью; вы просто не спрашиваете PHP в течение 20 лет, и он дает вам 19,99 ..., верно?

Edit2: Все, кажется, сводится к части о 1968 году;

  • 1970 г.; нашел его точным во всех тестах, которые я пробовал.
  • 1969 год; Найдено здесь (...ex: (2008-1969)/4 = 9.75...), а также упоминается здесь. Точно после 2-го года (+3 года) и далее.
  • 1968 год; как подробно описано ниже, это «нулевой год» високосных лет от времени Unix (1970). Звучит "правильно" (для меня), но совсем неточно.

person Christian    schedule 24.12.2010    source источник
comment
Обязательно используйте четыре пробела для форматирования кода, чтобы получить предварительно отформатированный текстовый блок с подсветкой синтаксиса.   -  person Justin Spahr-Summers    schedule 24.12.2010
comment
Я думал, вкладки тоже работают?   -  person Christian    schedule 24.12.2010
comment
Я думал это видно из последнего абзаца? Я должен получить 20, но я получаю 19,998630136986; Я понятия не имею, где я теряю точность.   -  person Christian    schedule 24.12.2010
comment
Это НИКОГДА не будет 20 из-за вашего странного поведения, исключающего високосный год   -  person ajreal    schedule 24.12.2010
comment
ajreal - Я не понимаю твою мысль. Я просто удаляю лишние секунды високосного года, можете ли вы объяснить немного больше, чем очевидное (мы все знаем, что это не 20)? Где странное поведение при удалении дополнительных секунд?   -  person Christian    schedule 24.12.2010


Ответы (2)


Может ли это быть связано с присущей PHP неточностью при управлении числами с плавающей запятой?

http://php.net/manual/en/language.types.float.php

person Luke Stevenson    schedule 24.12.2010

Вы должны заменить 1968 в своих вычислениях (откуда оно взялось?) на начало времени unix: 1970, и вы получите более точные результаты.

Изменить

Вы должны сделать intval, чтобы подсчитать количество високосных лет, которое должно быть целым числом:

return $time - (intval( (date('Y', $time) - 1969) / 4) * $LEAPDIFF);

Это даст вам правильные результаты в диапазоне +0 -> +68 , конец времени unix на 32-битной машине.

person Toto    schedule 24.12.2010
comment
Каждые четыре года бывает високосный год, 1972, 1976, 1980... чтобы рассчитать количество високосных лет с 1970 по год Y, я использую это: round((Y-1968)/4) пример: (1976-1968)/4 = 2. Причина в том, что 1970 (unix) не совпадает с високосным годом, поэтому я уменьшаю его, пока не доберусь до високосного года 0, то есть 1968 года. - person Christian; 24.12.2010
comment
Попробовав ваше предложение, я получил точные результаты. Я еще больше запутался :( - person Christian; 24.12.2010
comment
Я увеличил ставки с +20 до +60 лет и... получил точные результаты. Попробовал +80 и получил 0 (тогда как у меня получилось отрицательное число). - person Christian; 24.12.2010
comment
Если номер года указан в двузначном формате, значения от 00 до 69 отображаются на 2000–2069, а 70–99 — на 1970–1999. ...возможные отличия в 32-битных системах (возможные даты могут заканчиваться 19.01.2038 03:14:07). - person ajreal; 24.12.2010