06.01.2009, 14:43 | #1 |
совсем зелен
|
количество месяцев...
как быстрее и проще вычислить количество месяцев за период с первой даты по вторую???
|
|
06.01.2009, 16:00 | #2 |
Участник
|
в 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 функций |
|
06.01.2009, 16:33 | #3 |
Участник
|
AxPath://AOT/Classes/RAssetTableInterval_Month/monthDifference
|
|
|
За это сообщение автора поблагодарили: gefr (1). |
06.01.2009, 16:37 | #4 |
Moderator
|
Может, вот это пригодится:
Функция, вычисляющая разницу между датами. --- возвращает контейнер из семи значений: 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 |
Участник
|
Ты хоть смотрел туда?
Максим не надо гадость советовать. Вычсиление числа месяцев через цикл... Кроме того, он вообще не работает, если date dateFrom > dateTo.... Это такой антипаттерн... Что у меня просто слов не хватает... Никогда так не делайте! |
|
06.01.2009, 16:42 | #6 |
Участник
|
|
|
06.01.2009, 16:53 | #7 |
Участник
|
Кстати, спасибо за ссылку.
Здесь njd дал информацию о русском классе RHRMDateDiff Он вычисляет число лет, месяцев, дней. Причем число месяцев не может быть больше 12, а число дней не может быть больше 31. Т.е. для вычисления полного числа месяцев придется вычислять еще одно выражение (getYear() * 12 + getMonth()). Кроме того, и этот класс не работает, если дата начала больше даты конца. Кроме того, они зачем-то делают вычисления в момент инициализации класса (что теоретически не есть хорошо поскольку может значительно снизить эргономичность работы, если кто-то начнет инициализировать подобные структуры в init'е формы). |
|
06.01.2009, 16:54 | #8 |
Moderator
|
Никто и не предлагает этим заниматься. Для получения полного количества месяцев надо умножить полное кол-во лет (элемент 1 контейнера) на 12 и добавить месяцы неполного года (элемент 2).
Я просто выдаю все те величины, которые, как правило, не могут быть получены тривиальным путем, оставляя выбор пользователю функции выполнять заключительные тривиальные действия. Например, для получения общего количества недель срока надо всего лишь общее кол-во дней (элемент 6) разделить на 7. И т.п. Вот! А функцайка работает, возвращая отрицательные значения |
|
06.01.2009, 16:59 | #9 |
Участник
|
Упс, я помнил что русский класс имеется для вычиление разницы, но не помнил какой приношу извинения
|
|
06.01.2009, 17:11 | #10 |
Участник
|
Ок. Я неправильно выразился.
Получать число месяцев из функции, которая тратит время и на расчет числа дней... Это тоже изврат. Хотя и не такой, как расчет через цикл. Что касается расчета месяцев... Там предлагается: 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; } |
|
06.01.2009, 17:15 | #11 |
Участник
|
Цитата:
Проблема здесь в том, что именно требуется получить. Т.е. что подразумевается под термином "месяц" и, в меньшей степени, под термином "год". Разумеется, есть некоторые стандартные наработки. Например, функция 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 |
Участник
|
Цитата:
Обрати внимание на исходный вопрос: там не спрашивалась разница ДАТ. В иходном спрашивалось "количество месяцев". Кроме того, данный вопрос ИМЕЕТ решение. Только этих решений может быть несколько. Но решений конечное число. Правильно "данный вопрос имеет несколько решений". или "данный вопрос не имеет однозначного решения". |
|
06.01.2009, 17:24 | #13 |
Участник
|
Цитата:
Сообщение от 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; } 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; } |
|
06.01.2009, 17:27 | #14 |
Moderator
|
Цитата:
Сообщение от mazzy
Кстати, спасибо за ссылку.
Здесь njd дал информацию о русском классе RHRMDateDiff |
|
06.01.2009, 17:27 | #15 |
Участник
|
Цитата:
Сообщение от 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; } |
|
06.01.2009, 17:28 | #16 |
Участник
|
Цитата:
Сообщение от Gustav
Ну и в той же ветке чуть выше этот класс раскритикован
|
|
06.01.2009, 17:32 | #17 |
Moderator
|
Цитата:
Извиняюсь, если из-за меня слово за слово разгорелся этот флейм по поводу разницы дат |
|
06.01.2009, 17:40 | #18 |
Участник
|
Цитата:
Да, это будет более правильно. |
|
08.01.2009, 12:11 | #19 |
совсем зелен
|
а что за функция mthofYear??? ругается говорит не объявлена...
|
|
08.01.2009, 13:04 | #20 |
Участник
|
А блин... Извините.
mthofyr, конечно. исправил код в предыдущем сообщении. |
|
Теги |
дата |
|
|