Модераторы: skyboy, MoLeX, Aliance, ksnk

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> Два unix TIMESTAMP. Как найти разницу в месяцах? 
:(
    Опции темы
Wowa
  Дата 30.1.2005, 15:26 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
Group Icon


Профиль
Группа: Админ
Сообщений: 15017
Регистрация: 14.9.2000
Где: Винград

Репутация: 1
Всего: 290



Как найти разницу в месяцах между двумя датами заданных в unix TIMESTAMP? Если разница меньше одного месяца, то должно вывестись что-то типа 0.5, т.е. пол месяца.
Надо,чтобы функция корректно обрабатывала кол-во дней в месяцев и высокосные года.
Добавлено @ 15:28
Думаю реализация может быть такая:
Код

list($year1, $month1, $day1) = split('-', date('Y-m-d', $date1));
list($year2, $month2, $day2) = split('-', date('Y-m-d', $date2));
$diff = ($year2 * 12 + $month2) - ($year1 * 12 + $month1);

Добавлено @ 15:29
Но тут будет вычеслена только разница, если она равна хотя бы 1 месяцу.
PM WWW   Вверх
rMaveric
Дата 30.1.2005, 15:39 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 375
Регистрация: 18.7.2003

Репутация: 3
Всего: 6



Код

$delta = $date1 - $date2;
$data = getdate($delta);

echo $data["mon"]." ".$data["mday"];


Думаю должно так работать

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

Код

$delta = $data["year"]*12+$data["mon"]+$data["mday"]/30;


Это сообщение отредактировал(а) rMaveric - 30.1.2005, 15:43


--------------------
Моя благодарность не будет иметь границ. в определенных рамках конечно ;)
---
Веду IT блог
PM MAIL WWW ICQ   Вверх
Wowa
Дата 30.1.2005, 16:24 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
Group Icon


Профиль
Группа: Админ
Сообщений: 15017
Регистрация: 14.9.2000
Где: Винград

Репутация: 1
Всего: 290



Цитата(rMaveric @ 30.1.2005, 13:39)
Это просто вывод числовых значений разницы месяцев и дней, также моэжно добавить лет если необходимо А если нужно вывести только месяцы то


Код

$delta = $data["year"]*12+$data["mon"]+$data["mday"]/30;



Мы ведь не можем делить на 30, т.к. тогда потеряем точностьв наших расчетах. Дней может быть и 31 и 28 и 29.
PM WWW   Вверх
Mal Hack
Дата 30.1.2005, 16:56 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Мудрый...
****


Профиль
Группа: Участник Клуба
Сообщений: 9926
Регистрация: 15.2.2004

Репутация: 122
Всего: 261



Admin
mktime, когда посчитаешь результат пропустишь его через date() для получения YYY=MM-DD
PM ICQ   Вверх
rMaveric
Дата 30.1.2005, 16:59 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 375
Регистрация: 18.7.2003

Репутация: 3
Всего: 6



В таком случае нам достаточно разделить на кол-вл месяцев в году и получим

Код

$delta = $data["year"]*12+$data["mon"]+$data["mday"]/intval(date("f", $delta));


Не... это не подойдет наверно.. т.к. здесь он бред выдаст... в зависимости от обеих дат... Но можно вставить вместа параметра $delta метку Юникса, на большую дату, тогда будет боелее логично, но я бы оставил деление на 30, т.к. какое из значений ставить месяца начала или месяца конца??? А у них в большинстве случаев будут разные кол-ва дней в году. А среднее значение...

365/12 = 30,4

Это сообщение отредактировал(а) rMaveric - 30.1.2005, 17:04


--------------------
Моя благодарность не будет иметь границ. в определенных рамках конечно ;)
---
Веду IT блог
PM MAIL WWW ICQ   Вверх
Mal Hack
Дата 30.1.2005, 17:07 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Мудрый...
****


Профиль
Группа: Участник Клуба
Сообщений: 9926
Регистрация: 15.2.2004

Репутация: 122
Всего: 261



Код

<?php

$d_1 = "04.08.2004 10:00";
$d_2 = "04.08.2004 11:00";

$da_1 = explode( " " , $d_1 );
$da_2 = explode( " " , $d_2 );

$dd_1 = explode( "." , $da_1[0] );
$dd_2 = explode( "." , $da_2[0] );

$dt_1 = explode( ":" , $da_1[1] );
$dt_2 = explode( ":" , $da_2[1] );

$r1 = mktime( $dt_1[0] , $dt_1[1] , 0 , $dd_1[1] , $dd_1[0] , $dd_1[2] );
$r2 = mktime( $dt_2[0] , $dt_2[1] , 0 , $dd_2[1] , $dd_2[0] , $dd_2[2] );

print "Date1 - Date2 = " . ( $r2 - $r1 ) . " sec";

?>

Можно сразу вычисления сделаь в mktime, она автоматом все переведет..

Это сообщение отредактировал(а) Mal Hack - 30.1.2005, 17:08
PM ICQ   Вверх
Wowa
Дата 30.1.2005, 17:18 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
Group Icon


Профиль
Группа: Админ
Сообщений: 15017
Регистрация: 14.9.2000
Где: Винград

Репутация: 1
Всего: 290



Mal Hack В этом примере получим мы секунды, а не месяцы. Секундны модно конвертировать в дни, а дни в месяцы нельзя. т.к. месяцы содержат разное кол-во дней.
PM WWW   Вверх
rMaveric
Дата 30.1.2005, 17:27 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 375
Регистрация: 18.7.2003

Репутация: 3
Всего: 6



2 Admin
Пожалуйста объясни что это должно быть... т.к. не понятна такая критичная скорость... Т.к. я не могу представить как вообще можно вычислить точный процент...


--------------------
Моя благодарность не будет иметь границ. в определенных рамках конечно ;)
---
Веду IT блог
PM MAIL WWW ICQ   Вверх
Wowa
Дата 30.1.2005, 17:45 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
Group Icon


Профиль
Группа: Админ
Сообщений: 15017
Регистрация: 14.9.2000
Где: Винград

Репутация: 1
Всего: 290



Это должны быть месяцы. Все просто. У меня в базе заложена цена какой-то услуги за 1 месяц.
Клиент может заказать услугу с 23 января по 1 января следующего года. Как вычислить теперь, сколько он должен заплатить?
PM WWW   Вверх
Wowa
Дата 30.1.2005, 19:09 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
Group Icon


Профиль
Группа: Админ
Сообщений: 15017
Регистрация: 14.9.2000
Где: Винград

Репутация: 1
Всего: 290



Не нашел пока ничего лучшего, кроме как прохода по всем месяцам, на которые заказана услуга и добавления номеров этих месяцев в массив. Чтобы затем через date получить кол-во дней в месяце по его ИД. Затем складываем все это и получаем кол-во дней на которые заказана услуга(согласно данным по месяцам).

Далее вычитаем из общего кол-ва дней, на которые заказана услуга(это мы можем получить совершенно точно) - кол-во дней, которые мы сейчас вычислили "по месяцам".

В результате мы имеем:
- кол-во месяцев, на которые была заказана услуга
- Остаток в днях
- знаем, сколько дней в конкретном месяце

Код

//Массив из месяцев на которые заказа услуга
$arr_mon=array();
array_push($arr_mon, $row['base_date_month']);
$count_mon=$row['base_date_month'];

for ($i=1; $i<$diff['month']; $i++) {
if ($count_mon==12) {$count_mon=0;};
$count_mon++;
if ($count_mon<10) {$count_mon='0'.$count_mon;};
array_push($arr_mon, $count_mon);
}
echo "<pre>";
print_r($arr_mon);
echo "</pre>";


PM WWW   Вверх
Wowa
Дата 31.1.2005, 03:40 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
Group Icon


Профиль
Группа: Админ
Сообщений: 15017
Регистрация: 14.9.2000
Где: Винград

Репутация: 1
Всего: 290



Итак. Испробовал я несколько алгоритмов. Один сложнее другого smile Надоело мне это и я всё удалил придумав новый алгоритм.

Итак, решение:
1. Вычисляем разницу в полных месяцах между датами заказа услуги
2. Полученное кол-во месяцев прибавляем к дата начала заказа и находим теперь уже разницу в днях между этой датой и датой окончания заказа.
3. Если разница в днях =0, то $total_price=$price*$month;
иначе $total_price=$price*month+$price/30.4167*разница в днях;

Есть только один недостаток, который мне так и не удалось избежать. Это точность цены за один день. Для ее определения я делю цену за месяц на 30.4167(365/12)
Интересно, насколько это критично для финансовой программы и как можно добиться бОльшей точности. Ведь мы используем не календарные месяцы, а свои, например, с 15 января по 15 февраля.
PM WWW   Вверх
tigrik
Дата 31.1.2005, 05:08 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 25
Регистрация: 5.9.2004

Репутация: 1
Всего: 3



Мы делали похожую систему. Вот код на Си.
На ПХП переделать легко. Единственно, что необходимо добавить - функция DecodeDate, которая разобьёт
TDateTime на год-месяц-день.

Код


#define TDateTime double
void DecodeDate (TDateTime date,int &Jahr, int &Monat, int &Tag){}
int    AnzahlTage(int AMonat, int AJahr);
bool    SchaltJahr(int AJahr);
void Trace(const char*name,const char*msg){}
//Gibt den Preis des Vertrages von Anfang bis Ende, mit Monatspreis von Betrag
double getPreis(TDateTime Anfang, TDateTime Ende, double Betrag)
{
      int AnfangJahr, AnfangMonat, ATag;
      int EndeJahr, EndeMonat, ETag;
      double BetragAnfang=Betrag;
      double BetragEnde=Betrag;
    double BetragJahr,BetragAnfangJahr,BetragEndeJahr;
 BetragJahr=BetragAnfangJahr=BetragEndeJahr=Betrag*12;
     
   bool KurzVertrag;
      //DecodeDate (TDateTime date,int &Jahr, int &Monat, int &Tag);
      DecodeDate(Anfang, AnfangJahr, AnfangMonat, ATag);
      DecodeDate(Ende, EndeJahr, EndeMonat, ETag);
         
      KurzVertrag=false;
      if((AnfangMonat==EndeMonat) && (AnfangJahr==EndeJahr))
      {
               /*Vertrag ist kuerzer als 1 Monat und liegt innerhalb eines Kalendarmonats*/
        KurzVertrag=true;

        return Betrag/(AnzahlTage(AnfangMonat,AnfangJahr)*(ETag-ATag));
      }      
      bool MonatAnfang_voll=true;
      bool MonatEnde_voll=true;
      if(ATag != 1)  
      {
 //Vertrag f?ngt nicht am Ersten des Monats an.
       BetragAnfang=(Betrag/AnzahlTage(AnfangMonat,AnfangJahr))* (AnzahlTage(AnfangMonat,AnfangJahr)-ATag);
       MonatAnfang_voll=false;
      }

      if(ETag != AnzahlTage(EndeMonat,EndeJahr))  {
    //Vertrag endet nicht am letzten Tag des Monats.
         BetragEnde=(Betrag/AnzahlTage(EndeMonat,EndeJahr))* (ETag);
         MonatEnde_voll=false;
      }
     
      if(AnfangJahr==EndeJahr)
      {
       return BetragAnfang+BetragEnde+Betrag*(EndeMonat-AnfangMonat);
      }
     
     
     
    //  DecodeDate(Anfang-Ende, AnzahlJahre, AnzahlMonate, AnzahlTage);
     
      if(AnfangMonat != 1)  
      {
        //Vertrag f?ngt nicht im ersten Monat an.
        if(!MonatAnfang_voll)
         BetragAnfangJahr=(12-AnfangMonat-1)*Betrag+BetragAnfang;
        else
         BetragAnfangJahr=(12-AnfangMonat)*Betrag;
       
     }
     
         if(EndeMonat != AnzahlTage(EndeMonat,EndeJahr))  
        {
          //Vertrag endet nicht am letzten Monat.
          BetragEnde=(Betrag/AnzahlTage(EndeMonat,EndeJahr))* (ETag);
          if(!MonatAnfang_voll)
             BetragAnfangJahr=(AnfangMonat-1)*Betrag+BetragEnde;
     else
          BetragAnfangJahr=(AnfangMonat)*Betrag;
         
       }
     
 //BetragAnfang - стоимость за первый неполный месяц
 //BetragEnde - стоимость за последний неполный месяц
 //MBetrag - стоимость за месяц;
 return BetragAnfangJahr+BetragEndeJahr+Betrag*((EndeJahr-AnfangJahr-1)*12);
}

/*
Gibt die Anzahl der Tage im Monat AMonat des Jahres AJahr zur?ck
*/
int    AnzahlTage(int AMonat, int AJahr)
{
     switch (AMonat){
            case     1:      {return 31;}
            case     2:      {if(SchaltJahr(AJahr))
                         {
                               return 29;
        }
                             else return 28;}
            case      3:      {return 31;}
            case      4:      {return 30;}
            case      5:      {return 31;}
            case      6:      {return 30;}
            case      7:      {return 31;}
            case      8:      {return 31;}
            case      9:      {return 30;}
            case      10:     {return 31;}
            case      11:     {return 30;}
            case      12:     {return 31;}
            default: {Trace("Warnung","Monat unbekannt!"); return 0;}
            }

}
/*
Sagt ob AJahr ein Schaltjahr ist
*/
bool    SchaltJahr(int AJahr)
{
     return ((((AJahr % 4)==0) && ((AJahr % 100)!=0)) || ((AJahr % 400)==0));
}



Это сообщение отредактировал(а) tigrik - 31.1.2005, 15:05
PM MAIL   Вверх
Akina
Дата 31.1.2005, 09:54 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Советчик
****


Профиль
Группа: Модератор
Сообщений: 20581
Регистрация: 8.4.2004
Где: Зеленоград

Репутация: 5
Всего: 454



Цитата(Admin @ 31.1.2005, 04:40)
Есть только один недостаток, который мне так и не удалось избежать. Это точность цены за один день. Для ее определения я делю цену за месяц на 30.4167(365/12)
Интересно, насколько это критично для финансовой программы и как можно добиться бОльшей точности.

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


--------------------
 О(б)суждение моих действий - в соответствующей теме, пожалуйста. Или в РМ. И высшая инстанция - Администрация форума.

PM MAIL WWW ICQ Jabber   Вверх
Wowa
Дата 31.1.2005, 13:53 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
Group Icon


Профиль
Группа: Админ
Сообщений: 15017
Регистрация: 14.9.2000
Где: Винград

Репутация: 1
Всего: 290



Т.е. это совершенно нормально, что стоимость одного дня в разный месяцах разная?
PM WWW   Вверх
Gold Dragon
Дата 31.1.2005, 14:02 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Призрачный
****


Профиль
Группа: Экс. модератор
Сообщений: 6753
Регистрация: 1.3.2004
Где: Россия, Тамбов

Репутация: 10
Всего: 71



это не нормально. smile

а почему просто не использовать 1/28, 1/29, 1/30, 1/31

например, полмесяца в феврале: 14/28=0,5 полмесяца в апреле: 15/30=0,5

если месяц переходящий (с 15 февраля по 15 марта) то тогда 14/28+15/31 погрешность конечно будет, но не большая

ну и в чём проблема


--------------------
Нельзя жить в прошлом, оно уже прошло.
Нельзя жить в будущем, оно ещё не наступило.
Нужно жить в настоящем, помня прошлое и думая о будущем!
PM MAIL WWW ICQ   Вверх
Страницы: (3) Все [1] 2 3 
Ответ в темуСоздание новой темы Создание опроса
Правила форума "PHP"
Aliance
IZ@TOP
skyboy
SamDark
MoLeX

Новичкам:

  • PHP редакторы собираются и обсуждаются здесь
  • Электронные книги по PHP, документацию можно найти здесь
  • Интерпретатор PHP, полную документацию можно скачать на PHP.NET

Важно:

  • Не брезгуйте пользоваться тегами [code=php]КОД[/code] для повышения читабельности текста/кода.
  • Перед созданием новой темы воспользуйтесь поиском и загляните в FAQ
  • Действия модераторов можно обсудить здесь

Внимание:

  • Темы "ищу скрипт", "подскажите скрипт" и т.п. будут переноситься в форум "Web-технологии"
  • Темы с именами: "Срочно", "помогите", "не знаю как делать" будут УДАЛЯТЬСЯ

Если Вам понравилась атмосфера форума, заходите к нам чаще! С уважением, IZ@TOP, skyboy, SamDark, MoLeX, awers.

 
0 Пользователей читают эту тему (0 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | PHP: Общие вопросы | Следующая тема »


 




[ Время генерации скрипта: 0.0619 ]   [ Использовано запросов: 22 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.