AXForum  
Вернуться   AXForum > Microsoft Dynamics AX > DAX: Программирование
All
Забыли пароль?
Зарегистрироваться Правила Справка Пользователи Сообщения за день Поиск

 
 
Опции темы Поиск в этой теме Опции просмотра
Старый 06.01.2009, 14:43   #1  
V777 is offline
V777
совсем зелен
 
249 / 10 (1) +
Регистрация: 15.04.2008
количество месяцев...
как быстрее и проще вычислить количество месяцев за период с первой даты по вторую???
Старый 06.01.2009, 16:00   #2  
mazzy is offline
mazzy
Участник
Аватар для mazzy
Лучший по профессии 2015
Лучший по профессии 2014
Лучший по профессии AXAWARD 2013
Лучший по профессии 2011
Лучший по профессии 2009
 
29,472 / 4494 (208) ++++++++++
Регистрация: 29.11.2001
Адрес: Москва
Записей в блоге: 10
в ax4 стандартной функции вроде нет.
стоит попытаться через mthonyr.

Что-нибудь вроде
X++:
{
   Date dateFrom = 01\06\1995;
   Date dateTo = 01\04\2008;
   int years = year(dateTo) - year(dateFrom);
   int month = mthofyr(DateTo) - mthofYear(dateFrom);

   return ((years * 12) + month;
}

В ax2009 тип Date изменен на dateTime. Поэтому стоит посмотреть в сторону .net функций
__________________
полезное на axForum, github, vk, coub.
Старый 06.01.2009, 16:33   #3  
belugin is offline
belugin
Участник
Аватар для belugin
Сотрудники Microsoft Dynamics
Лучший по профессии 2017
Лучший по профессии 2015
Лучший по профессии 2014
Лучший по профессии 2011
Лучший по профессии 2009
 
4,622 / 2925 (107) +++++++++
Регистрация: 16.01.2004
Записей в блоге: 5
AxPath://AOT/Classes/RAssetTableInterval_Month/monthDifference
За это сообщение автора поблагодарили: gefr (1).
Старый 06.01.2009, 16:37   #4  
Gustav is offline
Gustav
Moderator
Аватар для Gustav
SAP
Лучший по профессии 2009
 
1,858 / 1152 (42) ++++++++
Регистрация: 24.01.2006
Адрес: Санкт-Петербург
Записей в блоге: 19
Может, вот это пригодится:

Функция, вычисляющая разницу между датами.

--- возвращает контейнер из семи значений:
1. полные годы разницы - от 0 до бесконечности
2. полные месяцы (свыше полных лет) - от 0 до 11
3. дни неполного месяца (свыше полных месяцев) - от 0 до 30
4. недели месяца (свыше полных месяцев) - от 0 до 4
5. дни неполной недели (свыше полных недель) - от 0 до 6
6. общей кол-во дней разности - от 0 до бесконечности
7. дни неполного года - от 0 до 365
Старый 06.01.2009, 16:39   #5  
mazzy is offline
mazzy
Участник
Аватар для mazzy
Лучший по профессии 2015
Лучший по профессии 2014
Лучший по профессии AXAWARD 2013
Лучший по профессии 2011
Лучший по профессии 2009
 
29,472 / 4494 (208) ++++++++++
Регистрация: 29.11.2001
Адрес: Москва
Записей в блоге: 10
Цитата:
Сообщение от belugin Посмотреть сообщение
AxPath://AOT/Classes/RAssetTableInterval_Month/monthDifference
Ты хоть смотрел туда?
Максим не надо гадость советовать.
Вычсиление числа месяцев через цикл...
Кроме того, он вообще не работает, если date dateFrom > dateTo....

Это такой антипаттерн... Что у меня просто слов не хватает... Название: bad.gif
Просмотров: 4978

Размер: 2.7 Кб
Никогда так не делайте!
__________________
полезное на axForum, github, vk, coub.
Старый 06.01.2009, 16:42   #6  
mazzy is offline
mazzy
Участник
Аватар для mazzy
Лучший по профессии 2015
Лучший по профессии 2014
Лучший по профессии AXAWARD 2013
Лучший по профессии 2011
Лучший по профессии 2009
 
29,472 / 4494 (208) ++++++++++
Регистрация: 29.11.2001
Адрес: Москва
Записей в блоге: 10
Цитата:
Сообщение от Gustav Посмотреть сообщение
Погоди.

Разница между месяцами существенно проще разницы между датами (потому что нет проблемы 29 февраля).
Поэтому вычислять число месяцев через число дней... Это тоже изврат... Конечно не такой как мегаизврат с циклом... Но...
__________________
полезное на axForum, github, vk, coub.
Старый 06.01.2009, 16:53   #7  
mazzy is offline
mazzy
Участник
Аватар для mazzy
Лучший по профессии 2015
Лучший по профессии 2014
Лучший по профессии AXAWARD 2013
Лучший по профессии 2011
Лучший по профессии 2009
 
29,472 / 4494 (208) ++++++++++
Регистрация: 29.11.2001
Адрес: Москва
Записей в блоге: 10
Кстати, спасибо за ссылку.
Здесь njd дал информацию о русском классе RHRMDateDiff

Он вычисляет число лет, месяцев, дней.
Причем число месяцев не может быть больше 12, а число дней не может быть больше 31.
Т.е. для вычисления полного числа месяцев придется вычислять еще одно выражение (getYear() * 12 + getMonth()).
Кроме того, и этот класс не работает, если дата начала больше даты конца.

Кроме того, они зачем-то делают вычисления в момент инициализации класса (что теоретически не есть хорошо поскольку может значительно снизить эргономичность работы, если кто-то начнет инициализировать подобные структуры в init'е формы).
__________________
полезное на axForum, github, vk, coub.
Старый 06.01.2009, 16:54   #8  
Gustav is offline
Gustav
Moderator
Аватар для Gustav
SAP
Лучший по профессии 2009
 
1,858 / 1152 (42) ++++++++
Регистрация: 24.01.2006
Адрес: Санкт-Петербург
Записей в блоге: 19
Цитата:
Сообщение от mazzy Посмотреть сообщение
Поэтому вычислять число месяцев через число дней... Это тоже изврат...
Никто и не предлагает этим заниматься. Для получения полного количества месяцев надо умножить полное кол-во лет (элемент 1 контейнера) на 12 и добавить месяцы неполного года (элемент 2).

Я просто выдаю все те величины, которые, как правило, не могут быть получены тривиальным путем, оставляя выбор пользователю функции выполнять заключительные тривиальные действия. Например, для получения общего количества недель срока надо всего лишь общее кол-во дней (элемент 6) разделить на 7. И т.п.
Цитата:
Сообщение от mazzy Посмотреть сообщение
Кроме того, и этот класс не работает, если дата начала больше даты конца.
Вот! А функцайка работает, возвращая отрицательные значения
Старый 06.01.2009, 16:59   #9  
belugin is offline
belugin
Участник
Аватар для belugin
Сотрудники Microsoft Dynamics
Лучший по профессии 2017
Лучший по профессии 2015
Лучший по профессии 2014
Лучший по профессии 2011
Лучший по профессии 2009
 
4,622 / 2925 (107) +++++++++
Регистрация: 16.01.2004
Записей в блоге: 5
Упс, я помнил что русский класс имеется для вычиление разницы, но не помнил какой приношу извинения
Старый 06.01.2009, 17:11   #10  
mazzy is offline
mazzy
Участник
Аватар для mazzy
Лучший по профессии 2015
Лучший по профессии 2014
Лучший по профессии AXAWARD 2013
Лучший по профессии 2011
Лучший по профессии 2009
 
29,472 / 4494 (208) ++++++++++
Регистрация: 29.11.2001
Адрес: Москва
Записей в блоге: 10
Цитата:
Сообщение от Gustav Посмотреть сообщение
Никто и не предлагает этим заниматься.
Ок. Я неправильно выразился.
Получать число месяцев из функции, которая тратит время и на расчет числа дней...
Это тоже изврат. Хотя и не такой, как расчет через цикл.

Что касается расчета месяцев...
Там предлагается:
X++:
ms = ( year(dtEnd) * 12 + mthOfYr(dtEnd) )
   - ( year(dtBeg) * 12 + mthOfYr(dtBeg) ); // предварительная разница в месяцах
Мне кажется, что мой код будет выполняться чуть быстрее, поскольку умножение выполняется только один раз.

Другое дело, что там учитываются полные месяцы.
Т.е. тот алгоритм выдаст 0 полных месяцев для дат 21.01.09, 18.08.09 (день месяца даты начала больше дня месяца даты окончания), а мой алгоритм выдаст 1 месяц.

Но если надо учитывать полные месяцы, то опять же лучше избегать вычисления разницы между датами. сделать так:
X++:
{
   Date dateFrom = 01\06\1995;
   Date dateTo = 01\04\2008;
   int years = year(dateTo) - year(dateFrom);
   int month = mthofyr(DateTo) - mthofYr(dateFrom);
   int month_correction = dayofmth(DateFrom) > dayofmth(DateTo) ? sign(DateFrom - DateTo) : 0;

   return ((years * 12) + month + month_correction;
}
__________________
полезное на axForum, github, vk, coub.
Старый 06.01.2009, 17:15   #11  
Владимир Максимов is offline
Владимир Максимов
Участник
КОРУС Консалтинг
 
1,700 / 1195 (43) ++++++++
Регистрация: 13.01.2004
Записей в блоге: 3
Цитата:
Сообщение от mazzy Посмотреть сообщение
Разница между месяцами существенно проще разницы между датами (потому что нет проблемы 29 февраля).
Наоброт. Как только возникает задача получение разницы между датами в формате "Лет-Месяцев-Дней" вместо простой разницы дней, то возникает такое количество "наворотов", что без "пол-литры" не разберешся.

Проблема здесь в том, что именно требуется получить. Т.е. что подразумевается под термином "месяц" и, в меньшей степени, под термином "год".

Разумеется, есть некоторые стандартные наработки. Например, функция IntvNo() или тот же класс RHRMDateDiff(). Вопрос только в том, ЧТО они считают?

================================================================

Вопрос

Как получить разницу двух дат в формате: лет, месяцев, дней

Ответ

В общем случае, данный вопрос не имеет решения.

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

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

Для лучшего понимания проблемы рассмотрим простой пример.

Надо определить разницу дат между 30 января и 2 апреля одного 2008 года.

Если бы задача заключалась в определении количества дней, то все решалось бы простым вычитанием


X++:
fromDate = 30\01\2008;
toDate = 02\04\2008;

print  toDate - fromDate;     // 63 дня
pause;

А как определить количество месяцев? Результат будет существенно зависеть от того, как именно будет определяться один месяц. Возможно несколько идеологий расчета:

Вариант 1

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

Под термином "месяц" в процессе прибавления подразумевается такая операция, в результате которой номер дня остается тот же самый, а номер месяца увеличивается на 1. Если у нового месяца нет такой даты, то устанавливается дата равная последнему дню нового месяца.

Это значит, что если прибавить один месяц к 30 января, то получим 29 февраля (2008 год - високосный), поскольку в феврале нет 30 числа.

Затем прибавляем к 29 февраля еще один месяц, получаем 29 марта. Прибавлять еще один месяц уже не надо, поскольку результат будет заведомо больше 2 апреля.

Между 29 марта и 2 апреля остается 4 дня. Значит, результат будет 2 месяца и 4 дня.

Заметьте, что в не високосном году результат был бы 2 месяца и 5 дней

Обратите внимание на тот факт, что если начальная дата равна 29, 30 или 31 января результат был бы один и тот же! Поскольку прибавление одного месяца давало бы все то же 29 февраля. Получается парадоксальная ситуация - количество дней разное, а результат одинаковый.


Вариант 2

Алгоритм похож на "Вариант 1", но прибавлять будем не по одному месяцу за раз, а сразу прибавим столько месяцев, чтобы оказаться как можно ближе к конечной дате. Т.е. прибавим к 30 января сразу 2 месяца и получим 30 марта.

Между 30 марта и 2 апреля остается 3 дня. Значит, результат будет 2 месяца и 3 дня.

Заметьте, что если бы конечным месяцем был бы не апрель, а март, то данный вариант расчета ничем не отличался бы от "Варианта 1".

Именно этот алгоритм заложен в классе RHRMDateDiff()

Вариант 3

Под термином "месяц" будем понимать именно календарный месяц. Т.е. февраль - это интервал от 01 февраля до 29 февраля, март - это интервал от 01 марта до 31 марта.

В этом случае имеем 2 полных месяца - февраль и март. И "остатки" от граничных месяцев: 1 день до конца января и 2 дня апреля. Значит, результат будет 2 месяца и 3 дня.

Но в данном случае повезло. Оставшихся дней явно не хватает для полного месяца. А если бы оставшихся дней было бы, например, 40 (с 10 января по 20 апреля)? Встал бы вопрос, сколько дней надо выделить из этого количества дней, чтобы получить еще 1 месяц? Берем количество дней в январе (месяце начала периода) или в апреле (месяце конца периода)?


Вариант 4

Принимаем, что все месяцы имеют одинаковое количество дней, которое вычисляется по следующей формуле:


(365+365+365+366)/4/12 = 30.4375

Тогда количество месяцев - это просто отношение количества дней к данной константе, округленное до целого. Значит, результат будет 2 месяца и 2 дня.


Могут быть и другие варианты расчета.


Как видите, результат существенно зависит от того, что именно понимается под термином "месяц". Точнее, как именно этот самый месяц выделяется в заданном диапазоне. Причем, даже нельзя сказать, что один способ является "правильным", а другие "не правильные". Они все "правильные". Но в рамках определенной идеологии.

Другими словами, вопрос расчета интервала в формате "лет, месяцев, дней" заключается не столько в коде, сколько в идеологии (алгоритме) расчета. Как только будет принята определенная идеология расчета, запрограммировать ее не составит труда.

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

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

Вы можете поискать уже готовые примеры расчета на данном сайте или в интернете. Но всегда следует иметь в виду, что все эти примеры кодируют определенную идеологию определения месяца и года. К сожалению, как именно (по какой идеологии) происходит это определение из кода далеко не всегда видно. Поэтому, результат работы найденных примеров может оказаться далек от ожидаемых Вами. Каждый пример следует тщательно протестировать для определения его пригодности под Вашу конкретную задачу.
За это сообщение автора поблагодарили: mazzy (2), lev (1), petr (2), oip (2), Gustav (5).
Старый 06.01.2009, 17:22   #12  
mazzy is offline
mazzy
Участник
Аватар для mazzy
Лучший по профессии 2015
Лучший по профессии 2014
Лучший по профессии AXAWARD 2013
Лучший по профессии 2011
Лучший по профессии 2009
 
29,472 / 4494 (208) ++++++++++
Регистрация: 29.11.2001
Адрес: Москва
Записей в блоге: 10
Цитата:
Сообщение от Владимир Максимов Посмотреть сообщение
Вопрос

Как получить разницу двух дат в формате: лет, месяцев, дней

Ответ

В общем случае, данный вопрос не имеет решения.

Обрати внимание на исходный вопрос: там не спрашивалась разница ДАТ.
В иходном спрашивалось "количество месяцев".

Кроме того, данный вопрос ИМЕЕТ решение. Только этих решений может быть несколько. Но решений конечное число.

Правильно "данный вопрос имеет несколько решений".
или "данный вопрос не имеет однозначного решения".
__________________
полезное на axForum, github, vk, coub.
Старый 06.01.2009, 17:24   #13  
mazzy is offline
mazzy
Участник
Аватар для mazzy
Лучший по профессии 2015
Лучший по профессии 2014
Лучший по профессии AXAWARD 2013
Лучший по профессии 2011
Лучший по профессии 2009
 
29,472 / 4494 (208) ++++++++++
Регистрация: 29.11.2001
Адрес: Москва
Записей в блоге: 10
Цитата:
Сообщение от mazzy Посмотреть сообщение

Но если надо учитывать полные месяцы, то опять же лучше избегать вычисления разницы между датами. сделать так:
X++:
{
   Date dateFrom = 01\06\1995;
   Date dateTo = 01\04\2008;
   int years = year(dateTo) - year(dateFrom);
   int month = mthofyr(DateTo) - mthofYr(dateFrom);
   int month_correction = dayofmth(DateFrom) > dayofmth(DateTo) ? sign(DateFrom - DateTo) : 0;

   return ((years * 12) + month + month_correction;
}
А блин... В Аксапте sign какой-то странный. Он выдает только два значения +1 или -1. Правильный код с учетом этой багофичи:

X++:
{
   Date dateFrom = 01\06\1995;
   Date dateTo = 01\04\2008;
   int years = year(dateTo) - year(dateFrom);
   int month = mthofyr(DateTo) - mthofYr(dateFrom);
   int month_correction = (DateFrom == DateTo) ? 0 : (dayofmth(DateFrom) > dayofmth(DateTo) ? sign(DateFrom - DateTo) : 0);

   return ((years * 12) + month + month_correction;
}
__________________
полезное на axForum, github, vk, coub.
Старый 06.01.2009, 17:27   #14  
Gustav is offline
Gustav
Moderator
Аватар для Gustav
SAP
Лучший по профессии 2009
 
1,858 / 1152 (42) ++++++++
Регистрация: 24.01.2006
Адрес: Санкт-Петербург
Записей в блоге: 19
Цитата:
Сообщение от mazzy Посмотреть сообщение
Кстати, спасибо за ссылку.
Здесь njd дал информацию о русском классе RHRMDateDiff
Ну и в той же ветке чуть выше этот класс раскритикован
Старый 06.01.2009, 17:27   #15  
mazzy is offline
mazzy
Участник
Аватар для mazzy
Лучший по профессии 2015
Лучший по профессии 2014
Лучший по профессии AXAWARD 2013
Лучший по профессии 2011
Лучший по профессии 2009
 
29,472 / 4494 (208) ++++++++++
Регистрация: 29.11.2001
Адрес: Москва
Записей в блоге: 10
Цитата:
Сообщение от mazzy Посмотреть сообщение
А блин... В Аксапте sign какой-то странный. Он выдает только два значения +1 или -1. Правильный код с учетом этой багофичи:

X++:
{
   Date dateFrom = 01\06\1995;
   Date dateTo = 01\04\2008;
   int years = year(dateTo) - year(dateFrom);
   int month = mthofyr(DateTo) - mthofYr(dateFrom);
   int month_correction = (DateFrom == DateTo) ? 0 : (dayofmth(DateFrom) > dayofmth(DateTo) ? sign(DateFrom - DateTo) : 0);

   return ((years * 12) + month + month_correction;
}
а вот с оптимизацией производительности

X++:
{
   Date dateFrom = 01\06\1995;
   Date dateTo = 01\04\2008;
   int years;
   int month;
   int month_correction;

   if(DateFrom == DateTo)
      return 0;

   years = year(dateTo) - year(dateFrom);
   month = mthofyr(DateTo) - mthofYr(dateFrom);
   month_correction = dayofmth(DateFrom) > dayofmth(DateTo) ? sign(DateFrom - DateTo) : 0;

   return ((years * 12) + month + month_correction;
}
__________________
полезное на axForum, github, vk, coub.
Старый 06.01.2009, 17:28   #16  
mazzy is offline
mazzy
Участник
Аватар для mazzy
Лучший по профессии 2015
Лучший по профессии 2014
Лучший по профессии AXAWARD 2013
Лучший по профессии 2011
Лучший по профессии 2009
 
29,472 / 4494 (208) ++++++++++
Регистрация: 29.11.2001
Адрес: Москва
Записей в блоге: 10
Цитата:
Сообщение от Gustav Посмотреть сообщение
Ну и в той же ветке чуть выше этот класс раскритикован
блин... вот ведь уроды... спасибо.
__________________
полезное на axForum, github, vk, coub.
Старый 06.01.2009, 17:32   #17  
Gustav is offline
Gustav
Moderator
Аватар для Gustav
SAP
Лучший по профессии 2009
 
1,858 / 1152 (42) ++++++++
Регистрация: 24.01.2006
Адрес: Санкт-Петербург
Записей в блоге: 19
Цитата:
Сообщение от mazzy Посмотреть сообщение

Обрати внимание на исходный вопрос: там не спрашивалась разница ДАТ.
В иходном спрашивалось "количество месяцев".
Хоть и не мне, но согласен. Я дал ссылку на свою функцию, потому что она в числе прочего и этот вопрос решает. А вдруг человеку захочется большего по ходу?

Извиняюсь, если из-за меня слово за слово разгорелся этот флейм по поводу разницы дат
Старый 06.01.2009, 17:40   #18  
Владимир Максимов is offline
Владимир Максимов
Участник
КОРУС Консалтинг
 
1,700 / 1195 (43) ++++++++
Регистрация: 13.01.2004
Записей в блоге: 3
Цитата:
Сообщение от mazzy Посмотреть сообщение

Обрати внимание на исходный вопрос: там не спрашивалась разница ДАТ.
В иходном спрашивалось "количество месяцев".
Это без разницы. Все-равно ведь все упирается в то, что есть "месяц". Разницу чего надо посчитать? Т.е. по каким правилам выделять эти самые "месяца"?

Цитата:
Сообщение от mazzy Посмотреть сообщение
Кроме того, данный вопрос ИМЕЕТ решение. Только этих решений может быть несколько. Но решений конечное число.

Правильно "данный вопрос имеет несколько решений".
или "данный вопрос не имеет однозначного решения".
Да, это будет более правильно.
Старый 08.01.2009, 12:11   #19  
V777 is offline
V777
совсем зелен
 
249 / 10 (1) +
Регистрация: 15.04.2008
а что за функция mthofYear??? ругается говорит не объявлена...
Старый 08.01.2009, 13:04   #20  
mazzy is offline
mazzy
Участник
Аватар для mazzy
Лучший по профессии 2015
Лучший по профессии 2014
Лучший по профессии AXAWARD 2013
Лучший по профессии 2011
Лучший по профессии 2009
 
29,472 / 4494 (208) ++++++++++
Регистрация: 29.11.2001
Адрес: Москва
Записей в блоге: 10
А блин... Извините.
mthofyr, конечно.
исправил код в предыдущем сообщении.
__________________
полезное на axForum, github, vk, coub.
Теги
дата

 

Похожие темы
Тема Автор Раздел Ответов Посл. сообщение
Странное количество в строке журнала инвентаризации pitersky DAX: Функционал 7 16.01.2009 16:46
как отдельно учитывать фактическое и финансовое количество? romulis DAX: Функционал 4 08.02.2007 15:01
Количество знаков после запятой для количества в Закупке. dimit DAX: Функционал 18 20.11.2006 17:23
Функция возвращающая количество месяцев нужна, никто не видел?.. MironovI DAX: Программирование 3 29.09.2005 12:05
Закупка. Количество введенное в таблицу PurchLine не отображается в накладной ATimTim DAX: Программирование 15 21.06.2004 10:11

Ваши права в разделе
Вы не можете создавать новые темы
Вы не можете отвечать в темах
Вы не можете прикреплять вложения
Вы не можете редактировать свои сообщения

BB коды Вкл.
Смайлы Вкл.
[IMG] код Вкл.
HTML код Выкл.
Быстрый переход

Рейтинг@Mail.ru
Часовой пояс GMT +3, время: 22:46.