![]() |
![]() |
afal 08.08.2004 - 14:15 |
Нужно вычислить количество дней месяцев и лет в интервале двух дат. Работает вот такой алгоритм: ================================================================= Dim intYar As Integer Dim intDay As Integer Dim intMon As Integer Dim dblRez As Double dblRez = DateDiff("y", Nz(Me![GenExp]), Me![EnGnExp]) / 365.25 intYar = Fix(dblRez) dblRez = dblRez - intYar intDay = dblRez * 365.25 intMon = Fix(intDay / 30.5) intDay = (dblRez * 365.25 / 30.5 - intMon) * 30.5 Me!AllYr = intYar 'количество лет Me!AllMon = intMon 'количество месяцев Me!AllDay = intDay 'количество дней ================================================================= До 17 лет включительно считается все правильно. Но при интервале дат более указанного появляется ошибка, а именно считается на один день больше, потом с какого-то предела начинает считать на два дня больше и т.д. Конечно, можно ввести поправочные коэффициенты в этих интервалах дат, но это будет не красиво. Может кто сталкивался с такой задачей, подскажите варианты. Заранее благодарен. |
KAPACb 1 - 08.08.2004 - 15:13 |
Во всех субд кол-во дней вычисляется вычитанием из одной даты другую. Типа Days = Date2 - Date1 Если у тебя день, месяц, и год отдельными intами, то переведи их в дату. Функцию в Акцессе, для перевода дня, месяца, и года в date не помню. |
afal 2 - 08.08.2004 - 23:05 |
(1)То, что ты написал "Типа Days = Date2 - Date1", в VB выполняет функция DateDiff() и поля в ней GenExp, и EnGnExp имеют тип даты, но вопрос ты прочитал не внимательно. |
KAPACb 3 - 09.08.2004 - 03:42 |
Чувак, не тормози. Во первых можно делать без функций, а вычитанием. Во вторых что тебе мешает сделать две переменные date и вычислить кол-во дней? |
afal 4 - 09.08.2004 - 12:39 | KAPACb - видимо читать ты все-таки не умеешь дальше чем заглавие ветки. |
для afal 5 - 09.08.2004 - 14:39 | это ты тормозишь, а Карасик абсолютно прав. Зачем так извращаться? Тем паче, что у тебя из-за твоих дробей и возникает ошибка. Считаешь число дней, хранишь в массиве количество дней в каждом месяце(январь, февраль...) и еще високосные года учитываешь. Далее следует элементарная математика для детей дошкольного возраста. Элементарно, Ватсон. :-) |
KAPACb 6 - 09.08.2004 - 22:07 |
Сам алгоритм в корне неверный с его 365.25 дней в году и 30.5 дней в месяце. Вот так это должно выглядеть: шаг 1. DateResult = Me![EnGnExp]) - Me![GenExp]) шаг 2. перевод DateResult в год, месяц, число Это делает функция, какая в VB так делает, не помню, искать лень. |
IT 7 - 10.08.2004 - 05:56 | Data1-data2=Количество дней в VB это всегда так было(если обе переменные являются датами, иначе надо привести к типу DATE DATA2=DataValue(Data2)) |
afal 8 - 10.08.2004 - 12:30 | Вот как раз - то "перевод DateResult в год, месяц, число" и являются сутью вопроса, вернее даже год и месяц определяются безотказно, а именно число, т.е. количество дней оставшихся после определения целого количества лет и месяцев дают ошибку и то только при разнице дат более 17 лет. А что алгоритм не верный, так это и так ясно, иначе бы не было вопроса. Да есть такие функции в 1С, в С++, а вот в VB я такого не нашел, поэтому и спросил, кто знает. Но исключительная уклончивость объяснений позволяет предпологать, что не знает ни кто. Но тем не менее, хоть поговорили ;) |
KAPACb 9 - 10.08.2004 - 13:08 | проверь, делается ли это функциями Month(Date), Year(Date), Day(Date) |
для afal 10 - 10.08.2004 - 14:18 |
Кстати, еще раз субж перечитал... Один вопрос(на первый взгляд оЧЧень глупый): с точки зрения задачи что такое "месяц" и "год", сколько в них дней(постоянная ли величина или как в действительности, переменная)? Я вроде в посте №5 предложил алгоритм... |
KAPACb 11 - 10.08.2004 - 16:20 |
Мазафака, я ошибся в 6 и в 9. Date2 - Date1 - это, естественно, не дата а именно количество дней, разница в днях между двумя датами. Тебе же надо не просто количество дней, например,648, а именно разницу в годах, месяцах и днях? Короче, решается проблема видимо так: YearResult = Year(Date2) - Year(Date1) MonthResult = Month(Date2) - Month(Date1) DayResult = Day(Date2) - Day(Date1) |
afal 12 - 10.08.2004 - 17:13 |
(10) "месяц" и "год"- величина переменная (отсюда и взялось количество дней 365.25, т.е. усредненное за четыре года), а реализацию алгоритма в посте 5 ты сам-то представляешь? Можно вообще занести в массив весь Григарианский календарь, но опять все сведется к вычислению разности номеров элементов массива и перевода в количество лет, месяцев и дней. И одна "маленькая неприятность" - заполнению этого массива придется посвятить весь остаток жизни (если еще уложишься). Написать функцию, которая считает приближенно (как, например, считают кадровики стаж) я и сам могу. Вопрос в том что бы воспользоваться уже имеющимися средствами в VB или, если кому не жалко, предложить собственную реализацию решения. (11) Например, нужно вычислить сколько лет, месяцев и дней между датами 16.03.1994г. и 01.06.1999г. Результат должен быть представлен в такой форме: "5 лет; 2 месяца; 16 дней". Из всего что ты написал правильно сработает только YearResult. Поскольку YearResult =5; MonthResult = 62, а DayResult=1907. Разница в представлении очевидна. Т.е. нужны опять таки преобразования к требуемой форме. Но уже радует, что хоть задача-то стала понятной ;) |
KAPACb 13 - 11.08.2004 - 02:42 | В акцессе случайно нет функции Month(s)Between(date,date)? |
KAPACb 14 - 11.08.2004 - 03:01 |
Ээээх, чувак, всё ж тебе разжовывать приходицца :) Вот тебе алгоритм. Даже не поленился акцесс запустить, проверить :) date1 = "16.03.1994" date2 = "01.06.1999" If Year(date2) > Year(date1) Then YearResult = Year(date2) - Year(date1) Else YearResult = Year(date1) - Year(date2) End If If Month(date2) > Month(date1) Then MonthResult = Month(date2) - Month(date1) Else MonthResult = Month(date1) - Month(date2) End If If Day(date2) > Day(date1) Then DayResult = Day(date2) - Day(date1) Else DayResult = Day(date1) - Day(date2) End If MsgBox (YearResult) MsgBox (MonthResult) MsgBox (DayResult) |
IT 15 - 11.08.2004 - 05:49 |
DAY между прочим возвращает не количество дней от рождества христова, я день даты Т.е. Day(16.03.1994)=16 Day(01.06.1999)=1 1-16=-15 Тоже самое и с остальным в 12 YearResult =5; MonthResult = 3; DayResult=-15 Кто хочет поспорить ? |
KAPACb 16 - 11.08.2004 - 09:46 |
(15) Дурень, прочитай внимательно 14. И причем тут количества дней от рождиства христова? А насчет кто хочет поспорить" если читать код не умеешь, засунь (14) в акцесс и запусти. И посмотри сколько будет DayResult 1 или -15. |
для afal 17 - 11.08.2004 - 09:48 |
12. А зачем весь Григорианский календарь вводить? Двумерный массив из 12 строк(по количеству месяцев) и двух столбцов. Строка массива: месяц, кол-во дней в месяце. Далее, чтоб не запутаться, отсчет можно вести от ближайшего(с округлением в меньшую сторону) високосного года(который /4). Вопрос только один, даже в пределах одного месяца... Положим, есть период с XX.YY.ZZZZ до XX.YY+1.ZZZZ. В зависимости от значения YY количество дней может разниться. Что в этом случае делать? Т.е., если промежуток более 4-х лет, то остаток может быть однозначно не определяем(если не сделать допущения). 14. Алгоритм некорректный. 15. Абсолютно верно. |
для afal 18 - 11.08.2004 - 09:49 | Тьфу, блин, 15 только наполовину верно. Как DAY -15 может возвращать??? |
для KAPACb 19 - 11.08.2004 - 09:51 | 14. А что, в ВБ нет функции а-ля ABS()? |
KAPACb 20 - 11.08.2004 - 09:52 |
Так, действительно, алгоритм (14) не верный. (0) Когда даты 31.12.2003 и 01.01.2004 - ты какой рещультат хочешь получить? |
KAPACb 21 - 11.08.2004 - 09:54 |
(19) Да, это я с утра не догнал, проверки ни к чему. конечно нужен абс(). Но в свете последних мыслей abs не поможет. Пример - даты 31.12.2003 и 01.01.2004. должен быть результат 0 лет, 0 месяцев, 1 день как я понимаю. |
afal 22 - 11.08.2004 - 10:03 |
(15) прошу прощения, в (12) я подставил результаты функции DateDiff(). (14) По представленному тобой коду получается, что YearResult =5; MonthResult = 3; DayResult=15. Что не соответствует действительности, поскольку на самом деле MonthResult = 2, трем он будет равен, только когда исполнится 16.06.1999. Поэтому нужно писать еще одно условие, учитывающее это обстаятельство. Функции подобной "Month(s)Between(date,date)", я не знаю и как раз хотел узнать, т.е. как я писал в (12), "воспользоваться уже имеющимися средствами в VB". |
для KAPACb 23 - 11.08.2004 - 10:14 | Проблема, насколько я понимаю, в том, как считать остаток от не полных четырех лет. |
afal 24 - 11.08.2004 - 10:23 | (20) В (0) как раз и получится 1 день. Поскольку разница между двумя датами там считается функцией DateDiff() в количестве дней между этими датами. И потом уже оттуда "вояются" месяцы и годы. |
afal 25 - 11.08.2004 - 10:30 | (23) Проблема, как считать остаток ДНЕЙ от полных лет и месяцев, которые в пределах разумного считаются безукоризненно. Я незнаю, конечно, возможно если считать в разных тысячелетиях и там будет ошибка, но практического применения это вряд ли найдет в большинстве случаев. |
Sergini 26 - 11.08.2004 - 11:38 |
Дроби, средние значения однозначно не пойдут, так как будут давать погрешности. Попробуй так: Function sss(A, B As Date) As String Dim intYar As Integer Dim intDay As Integer Dim intMon As Integer Dim dblRez As Double Dim DD As Date ' Твой вариант 'dblRez = DateDiff("y", A, B) / 365.25 'intYar = Fix(dblRez) 'dblRez = dblRez - intYar 'intDay = dblRez * 365.25 'intMon = Fix(intDay / 30.5) 'intDay = (dblRez * 365.25 / 30.5 - intMon) * 30.5 ' Мой Вариант intYar = DateDiff("yyyy", A, B) intMon = (DateDiff("m", A, B) - intYar * 12) DD = DateAdd("yyyy", intYar, A) DD = DateAdd("m", intMon, DD) intDay = DateDiff("y", DD, B) sss = intDay & " " & intMon & " " & intYar End Function |
Sergini 27 - 11.08.2004 - 12:00 | Правда это тоже работать будет условно, так как нужно уточнить что понимать под месяцем. Сколько нужно получить между датой 12/07/2004 и 11/08/2004? С одной стороны это месяц, так как прошло 30 дней, но не факт так как месяц может быть и 31 день. |
для afal 28 - 11.08.2004 - 13:22 |
Еще раз говорю. Есть какой-то промежуток, например: [13.03.2003,17.07.2014]. Разбиваешь на промежутки: [13.03.2003, 12.03.2011] - целые периоды по 4 года(по календарю!), то бишь, 8 лет; [01.01.2012, 31.12.2013] - число целых лет(по календарю!) внутри остатка, т.е., 2 года; [13.03.2011, 31.12.2011], [01.01.2014,17.07.2014] - два периода остатков, нужно считать с помощью массива, о котором я говорил выше. Данные два промежутка еще можно разделить на несколько с целью вычленения целого числа месяцев. + нужно анализировать, попадают ли остатки на високосный год(/4 или не /4). Мысль ясна? Ну повозиться чуть-чуть с кодированием придется, зато работать будет более корректно. |
для afal 29 - 11.08.2004 - 13:24 | В любом случае, погрешности в один день не избежать, но множиться при увеличении периода она не должна. |
afal 30 - 11.08.2004 - 15:49 | Sergini ты сам, наверное не проверял работу этого кода. Дело в том, что у тебя intMon всегда будет величина отрицательная, кроме случая, когда число и месяц начальной и конечной дат будут совпадать, поскольку (intYar * 12) > DateDiff("m", A, B) (число лет считается включительно, а число месяцев по фактическому количеству в интервале дат). Т.о. если считать разницу в датах с 01.06.89 по 01.01.99, то intYar=10, а на самом деле шести месяцев хватать не будет до десяти лет. Но само по себе применение функции DateAdd() интересная идея. Спасибо за нее.(28) И я еще раз говорю слишком сложную реализацию ты предлагаешь и то только теоретически. На практике все может оказаться значительно сложнее и многообразнее той картины, которая видится при теоретическом подходе. Тем более, что ты пророчишь: «В любом случае, погрешности в один день не избежать…», так это все уже работает в том виде, который был представлен изначально. Тогда лучше и проще считать по принципу расчета стажа кадровиками, принимая каждый месяц, не зависимо от года, в котором он находится, равным 30 дней. Почитай постинги выше, какие были предложения «в лёт» и во что они вылились потом. Задача не простая, а решение, предлагаемое тобой, слишком сложное, есть проще. |
Sergini 31 - 11.08.2004 - 16:13 |
2 afal. Я знаю, что функция которую я написал работает в данном варианте неверно и она и не должна работать верно. Для этого и написал, чтобы ты пояснил: что в твоём понимании месяц? Ведь месяц это интервал, причём в данном случае разный(29-31 день). Поэтому задача в этом варианте не имеет решений. Вот если бы ты принял за месяц интервалы типа 21.12.2002-21.01.2003. Т. е. принять за месяц промежуток от даты n этого месяца до даты n следующего, то такая задача уже бы имела решение. |
afal 32 - 11.08.2004 - 17:56 | Sergini я не совсем понял вопрос. Месяц в данной задаче это интервал времени, соответствующий одноименным значениям календаря. Т.е. если это январь, то это 31 день, если февраль, то в зависимости от года, но столько же сколько в календаре. Повторюсь, например, нужно вычислить сколько лет, месяцев и дней между датами 16.03.1994г. и 01.06.1999г. Результат должен быть представлен в такой форме: "5 лет; 2 месяца; 15 дней". Как здесь определить, что понимается под месяцем? Я понимаю месяц. Только считается он в данном случае не с 01.03.1994г., а с 16.03.1994г. Но мне представлялось, что эти вопросы как раз и должны учитывать встроенные функции языка. Видимо я ошибался. |
Sergini 33 - 12.08.2004 - 08:44 | Afal ты привёл не совсем удачный пример. А что будет в случае. с 05.02.1994 по 25.05.1994. Годов понятно 0. Месяцев целых 2(март, апрель). Ещё остаётся примерно 23 дня от февраля + 25дней от мая. Если их сложить, то они явно за месяц переваливают. Что же мы теперь подразумеваем под месяцем: можем принять 31, 28, 30... То есть если тебе нужно считать только целые месяца, то всё понятно(только количество дней будет больше 31 в некоторых случаях). В противном случае требуются уточнения. |
afal 34 - 12.08.2004 - 10:10 | Да Sergini ты совершенно прав. Но твой пример, можно ведь рассмотреть и в другом ракурсе. С 5 февраля по 5 мая будет три месяца со всем тем их количеством дней которое предусмотрено календарем и еще остаеся 20 дней мая, которые и пойдут в счет количества дней этого временного интервала. Я именно в таком плане хотел построить расчет. Вот и получится 0 лет 3 месяца 20 дней. Ведь, наверное, трудно оспаривать, что с 5 февраля по 5 мая будет три месяца? Другой вопрос по сколько дней будет в этих месяцах? По столько же как и в месяцах которые попадают в этот временной интервал минус единица. |
Sergini 35 - 12.08.2004 - 10:52 | А я о чём говорил? Цитирую:"...Вот если бы ты принял за месяц интервалы типа 21.12.2002-21.01.2003.Т. е. принять за месяц промежуток от даты n этого месяца до даты n следующего, то такая задача уже бы имела решение." |
Sergini 36 - 12.08.2004 - 11:16 |
А вот и решение: Function sss(A, B As Date) As String Dim intYar As Integer Dim intDay As Integer Dim intMon As Integer Dim DD As Date DD = DateSerial(Year(B), Month(B), Day(A)) intYar = DateDiff("yyyy", A, DD) intMon = (DateDiff("m", A, DD) - intYar * 12) intDay = DateDiff("y", DD, B) If intDay < 0 Then DD = DateSerial(Year(B - Day(B)), Month(B - Day(B)), Day(A)) intYar = DateDiff("yyyy", A, DD) intMon = (DateDiff("m", A, DD) - intYar * 12) intDay = DateDiff("y", DD, B) End If sss = intDay & " " & intMon & " " & intYar End Function |
afal 37 - 13.08.2004 - 11:14 | Я видимо не врубился в твое предложение принять за месяц интервалы дат. Скорее всего, это связано с тем, что в примере интервал не внутри года, а на смене лет. Ну да бог с ним. Все совершенно правильно, но, к сожалению код, который ты представил, в той форме как он есть, не работает как нужно. Например в интервале дат 23.06.96 – 12.02.03 получается 7 лет, ( минус)5 месяцев и 20 дней. Но это просто информация для тебя, что бы ты ни думал, что его где-то можно применять без изменений. Я еще не пытался исправить эту ситуацию, но думаю, что большого труда это не составит. Спасибо тебе большое за советы и помощь. |
Sergini 38 - 13.08.2004 - 15:38 |
Пожалуйста :) "Например в интервале дат 23.06.96 – 12.02.03 получается 7 лет, ( минус)5 месяцев и 20 дней" Попробуй тогда так: Function sss(A, B As Date) As String Dim intYar As Integer Dim intDay As Integer Dim intMon As Integer Dim DD As Date DD = DateSerial(Year(B), Month(B), Day(A)) intYar = DateDiff("m", A, DD) \ 12 intMon = (DateDiff("m", A, DD) - intYar * 12) intDay = DateDiff("y", DD, B) If intDay < 0 Then intMon = intMon - 1 DD = DateSerial(Year(B - Day(B)), Month(B - Day(B)), Day(A)) intYar = DateDiff("yyyy", A, DD) intDay = DateDiff("y", DD, B) End If sss = intDay & " " & intMon & " " & intYar End Function |
KAPACb 39 - 15.08.2004 - 04:04 | Похоже Sergini сделал верный алгоритм, снимаю шляпу |
afal 40 - 15.08.2004 - 10:13 |
Да Sergini, все правильно, но небольшая ошибка. Например в том же интервале дат 23.06.96 – 12.02.03 получается 7 лет, 7 месяцев и 20 дней, а должно 7 лет, 6 месяцев и 20 дней. Не следует вычислять intYar = DateDiff("yyyy", A, DD) через формат года, года в этом случае округляются до большего значения. Вот такой код, вроде работает во всех диапазонах верно: Function sss(A, B As Date) As String Dim intYar As Integer Dim intDay As Integer Dim intMon As Integer Dim DD As Date DD = DateSerial(Year(B), Month(B), Day(A)) intYar = DateDiff("m", A, DD) \ 12 intMon = (DateDiff("m", A, DD) - intYar * 12) intDay = DateDiff("y", DD, B) If intDay < 0 Then intMon = intMon - 1 DD = DateSerial(Year(B - Day(B)), Month(B - Day(B)), Day(A)) intDay = DateDiff("y", DD, B) End If sss = intDay & " " & intMon & " " & intYar End Function Спасибо тебе еще раз! |