|
![]() |
#1 |
Участник
|
Порылся в стандарте - есть такие фишки - например из печатной формы Т2
workDate = str2date(emplTable.SeniorityDate_RU(false, ""), 123); if (workDate) { dateDiff = new RHRMDateDiff(workDate, Today()); if (dateDiff.getValidate()) { if (dateDiff.getDays() > 0) { worddocument.insertFieldValue("ET_SenDay",dateDiff.getDays()); } if (dateDiff.getMonths() > 0) { worddocument.insertFieldValue("ET_SenMth",dateDiff.getMonths()); } if (dateDiff.getYears() > 0) { worddocument.insertFieldValue("ET_SenYr",dateDiff.getYears()); } } } |
|
![]() |
#2 |
Moderator
|
Еще одна разность между двумя датами в годах, месяцах, днях (и не только)
Может быть и есть где-то глубоко в Аксапте функция а-ля DateAdd, но я уже сваял свою, предназначенную только для интервала типа "месяц" (а в предложенном вчера VBA-шном алгоритме больше и не требуется - да и хорошо). Моя маленькая функция DateAddMonths корректно обрабатывает концовки месяцев, так же как и фирменные DateAdd из VBA и SQL Server.
Следующий джоб представляет эту функцию и небольшой тест для нее: X++: static void KKu_Job_6B11_TestDateAddMonths(Args _args) { int d, m; date dam; // -------------------------------------------------------------------------------------- // Returns a date containing a date to which a specified number of months has been added; // _months - number of months you want to add, it can be positive (to get dates in the future) or negative (to get dates in the past); // _date - date to which the months are added; date DateAddMonths(int _months, date _date) { int y2, m2, d2, ms; ms = ( year(_date) * 12 + mthOfYr(_date) ) + _months; y2 = (ms-1) div 12; m2 = ((ms-1) mod 12) + 1; d2 = min( dayOfMth(_date), dayOfMth( endMth( mkDate(1, m2, y2))) ); return mkDate(d2, m2, y2); } // -------------------------------------------------------------------------------------- ; // тестирование функции DateAddMonths на "критических" днях for (d=28; d<= 31; d++) // последние дни месяца (март 2004) { for (m=-12; m<= 12; m++) // плюс-минус год помесячно { dam = DateAddMonths( m, mkDate(d,3,2004)); if (d != dayOfMth(dam)) // для пущей наглядности выводим в инфолог только те даты, в которых значения дней не совпадают info( strfmt('от даты %1.03.04 отстоит ровно на %2 месяц. дата %3', d, m, dam) ); } } } Ну и раз появилась такая функция, значит появилась и возможность свой вчерашний алгоритм воплотить в X++. Что я и делаю, теперь уже полноценно присоединяясь своим "пятачком" к вкладу других коллег по ветке. Нижеследующий джоб использует рассмотренную выше функцию DateAddMonths для нужд другой функции - DateDiffYMDWD, которая для заданных начальной и конечной даты возвращает контейнер из пяти значений ("Year,Month,Day,Week,Day"), характеризующих разность между этими датами (см. комментарии в коде): X++: static void KKu_Job_6B11_TestDateDiff_2(Args _args) { container c; date DateAddMonths(int _months, date _date) { int y2, m2, d2, ms; ms = ( year(_date) * 12 + mthOfYr(_date) ) + _months; y2 = (ms-1) div 12; m2 = ((ms-1) mod 12) + 1; d2 = min( dayOfMth(_date), dayOfMth( endMth( mkDate(1, m2, y2))) ); return mkDate(d2, m2, y2); } //------------------------------------------------------------------------------------------ // разность между двумя датами в годах, месяцах, днях/неделях-днях // если конечная дата меньше начальной, то вычисляется разность назад (-) container DateDiffYMDWD(date _dateBeg, date _dateEnd) { date dtBeg, dtEnd, dtTest; int ms, ds, sgn; if (_dateBeg <= _dateEnd) { dtBeg = _dateBeg; dtEnd = _dateEnd; sgn = 1; } else // даты - наоборот, т.е. будет вычислена разность назад { dtBeg = _dateEnd; dtEnd = _dateBeg; sgn = -1; } ms = ( year(dtEnd) * 12 + mthOfYr(dtEnd) ) - ( year(dtBeg) * 12 + mthOfYr(dtBeg) ); // предварительная разница в месяцах dtTest = DateAddMonths(ms, dtBeg); // пробная дата на ms месяцев вперёд от начала ds = dtEnd - dtTest; // предварит-ная разница в днях в пределах последнего месяца (+/-) if (ds < 0) //ЕСЛИ предварит-но "перебрали" с полными месяцами от начала { ms = ms - 1; //ТО окончат-ная разница в месяцах dtTest = DateAddMonths(ms, dtBeg); // новая "пробная" дата ds = dtEnd - dtTest; //окончательная разница в днях (+) } return [(sgn*ms) div 12, // полные годы разницы - от 0 до бесконечности (sgn*ms) mod 12, // полные месяцы (свыше полных лет) - от 0 до 11 (sgn*ds) , // дни неполного месяца (свыше полных месяцев) - от 0 до 30 (sgn*ds) div 7 , // недели месяца (свыше полных месяцев) - от 0 до 4 (sgn*ds) mod 7 , // дни неполной недели (свыше полных недель) - от 0 до 6 (sgn*(dtEnd - dtBeg)), // общей кол-во дней разности - от от 0 до бесконечности (sgn*(dtEnd - DateAddMonths(ms - (ms mod 12), dtBeg)) ) // дни неполного года - от 0 до 365 ]; } //------------------------------------------------------------------------------------------ c = DateDiffYMDWD( mkDate(13,11,2006), mkDate(1,1,2005) ); info( strfmt('Difference between %1 and %2 :', mkDate(13,11,2006), mkDate(1,1,2005))); info( strfmt('years: %1 , months: %2 , daysOfMonth: %3 , weeksOfMonth: %4 , daysOfWeek: %5, allDays: %6, daysOfYear: %7', conpeek(c,1), conpeek(c,2), conpeek(c,3), conpeek(c,4), conpeek(c,5), conpeek(c,6), conpeek(c,7))); info('---------------------------------------------------'); c = DateDiffYMDWD( mkDate(13,11,2006), mkDate(1,1,2008) ); info( strfmt('Difference between %1 and %2 :', mkDate(13,11,2006), mkDate(1,1,2008))); info( strfmt('years: %1 , months: %2 , daysOfMonth: %3 , weeksOfMonth: %4 , daysOfWeek: %5, allDays: %6, daysOfYear: %7', conpeek(c,1), conpeek(c,2), conpeek(c,3), conpeek(c,4), conpeek(c,5), conpeek(c,6), conpeek(c,7))); } ![]() P.S. 13.11.06 - подправил функцию DateDiffYMDWD - теперь если конечная дата меньше начальной (_dateEnd < _dateBeg), то значения разности в возвращаемом контейнере будут со знаком "-" (т.е. разность "в прошлое"). А также добавил 6-й и 7-й элемент в контейнер. В итоге, имея такой контейнер, можно далее легко получать такие разницы между двумя датами, как: 1. в годах, месяцах, днях; 2. в годах, месяцах, неделях, днях; 3. в годах, днях; 4. в днях; Вариант 1 актуален для HR-менеджмента при подсчете трудового стажа сотрудника. Варианты 2-4 имеют "чисто теоретический характер", хотя всякое может быть... Не показаны некоторые другие возможные варианты, которые тривиально могут быть получены из имеющихся в контейнере значений: например, общий срок в полных месяцах = годы * 12 + месяцы (где "годы" - 1-е значение в контейнере, "месяцы" - 2-е), или общий срок в полных неделях = дни div 7 (где "дни" - 6-е значение в контейнере). |
|
|
За это сообщение автора поблагодарили: gl00mie (2). |
![]() |
#3 |
Moderator
|
Формулки для тёти бухгалтера (кадровика) в Excel
Пришлось тут наваять версию алгоритма для Excel на уровне формул в соседних колонках. Делал по мотивам своей вышеприведенной процедурки VBA_TestDifferenceBetweenTwoDates.
Произошло очередное укрепление убеждения в том, что разность между двумя датами - это кол-во полных месяцев + дополнительные дни (сверх полных месяцев). Всё остальное - полные годы, доп.месяцы (сверх полных лет), недели, кварталы и что еще заблагорассудится - можно получить простыми операциями деления или получения остатка от деления. Завязываю узелок на память: в виде файла и в виде формул (для русского Excel). В виде формул - для большей наглядности (не надо лезть в файл), а также для гостей форума, для которых файл может быть недоступен. A1: Дата 1 B1: Дата 2 C1: Полн.Месяцы предв. D1: Полн.Месяцы оконч. E1: Полн.Годы F1: Месяцы сверх полн.лет G1: Дни сверх полн. мес. A2: 23.09.1984 B2: 15.12.2011 C2: =(ГОД(B2)-ГОД(A2))*12+МЕСЯЦ(B2)-МЕСЯЦ(A2) D2: =C2+ЕСЛИ(B2-ДАТАМЕС(A2;C2)<0; ЕСЛИ(B2>A2;-1; 0); ЕСЛИ(B2>A2; 0; 1)) E2: =ОТБР(D2/12) F2: =D2-E2*12 G2: =B2-ДАТАМЕС(A2;D2) Разность (Дата 1 - Дата 2) может быть с любым знаком, формулы корректно считают и в плюс, и в минус. P.S.05.03.2012. Ну что ж, как часто бывает в подобных случаях, когда надо "быстро-быстро" и "вчера", после внедрения начинаешь рассуждать спокойно, литературку почитаешь, по Сети поползаешь и поймешь, что существует (и давно) решение гораздо более изящное. Так и в этот раз - нашлась в Excel суперподходящая под задачу функция РАЗНДАТ (в англ. DATEDIF; не путать с ф-цией DateDiff VBA - при похожем названии возможности несколько различаются). Функция РАЗНДАТ является недокументированной, поэтому не появляется в списках выбора, отсутствует в справке и существует в Excel в основном для совместимости с Лотусом 1-2-3. Функция РАЗНДАТ идеальна для вычисления возраста (количества полных лет), поскольку абсолютна точна (в отличие от встречающихся в И-нете предложений делить разницу в днях на 365 или 365.25), а также для вычисления стажа (годы, месяцы, дни). Почитать про функцию можно, например, здесь: http://www.excel2003.ru/vichislenie-...ili-staja.html: Цитата:
Синтаксис функции следующий:
РАЗНДАТ(начальная_дата; конечная_дата; способ_измерения) Самый интересный аргумент, конечно, последний. Он определяет, каким именно образом и в каких единицах будет измеряться интервал между начальной и конечной датами. Этот параметр может принимать следующие значения: "y" разница в полных годах "m" в полных месяцах "d" в полных днях "yd" разница в днях с начала года без учета лет "md" разница в днях без учета месяцев и лет "ym" разница в полных месяцах без учета лет "yd" - количество дней сверх полных лет (от 0 до 365) "md" - количество дней сверх полных месяцев (от 0 до 30) "ym" - количество месяцев сверх полных лет (от 0 до 11) Таким образом, полный интервал между двумя датами может быть представлен одним из следующих вариантов: * количество дней РАЗНДАТ(дата1,дата2,"d") (или просто разница дат без использования РАЗНДАТ: дата2 - дата1) * кол-во полных лет РАЗНДАТ(дата1,дата2,"y") + кол-во дней сверх полных лет РАЗНДАТ(дата1,дата2,"yd") * кол-во полных месяцев РАЗНДАТ(дата1,дата2," m") + кол-во дней сверх полных месяцев РАЗНДАТ(дата1,дата2,"md") * случай расчета стажа: кол-во полных лет РАЗНДАТ(дата1,дата2,"y") + кол-во полных месяцев сверх полных лет РАЗНДАТ(дата1,дата2,"ym") + кол-во дней сверх полных месяцев РАЗНДАТ(дата1,дата2,"md") Да, и конечная дата должна быть больше начальной даты, т.е. в минус функция РАЗНДАТ автоматически не считает (в этом случае следует поменять даты местами). Добавил в прилагаемый файл формулы с РАЗНДАТ. Последний раз редактировалось Gustav; 05.03.2012 в 10:32. |
|