Имя: Пароль:
1C
1С v8
Вычисление разности дат в годах, днях и месяцах запросом
, ,
0 Said_We
 
20.07.18
02:16
Наткнулся на алгоритм расчета количества дней месяцев и лет между датами
Книга знаний: Вычисление разности дат в годах, днях и месяцах запросом

Приводится короткая функция расчета алгоритмом из ЗиУП и потом очень большой запрос для СКД или отчетов. Суть запроса понятна, но собственно почему не написать короче как в функции источнике.

У меня получилось следующее:

ВЫБРАТЬ
    ДАТАВРЕМЯ(2009, 9, 21) КАК ДатаН,
    ДАТАВРЕМЯ(2010, 9, 20) КАК ДатаК
ПОМЕСТИТЬ ВТ_Периоды

ОБЪЕДИНИТЬ ВСЕ

ВЫБРАТЬ
    ДАТАВРЕМЯ(2009, 9, 21),
    ДАТАВРЕМЯ(2010, 10, 20)

ОБЪЕДИНИТЬ ВСЕ

ВЫБРАТЬ
    ДАТАВРЕМЯ(2009, 9, 21),
    ДАТАВРЕМЯ(2010, 3, 20)

ОБЪЕДИНИТЬ ВСЕ

ВЫБРАТЬ
    ДАТАВРЕМЯ(2009, 9, 21),
    ДАТАВРЕМЯ(2012, 3, 20)

ОБЪЕДИНИТЬ ВСЕ

ВЫБРАТЬ
    ДАТАВРЕМЯ(2010, 10, 20),
    ДАТАВРЕМЯ(2010, 10, 20)

ОБЪЕДИНИТЬ ВСЕ

ВЫБРАТЬ
    ДАТАВРЕМЯ(2010, 10, 20),
    ДАТАВРЕМЯ(2010, 10, 19)
;

////////////////////////////////////////////////////////////////////////////////
ВЫБРАТЬ
    ВТ_Периоды.ДатаН,
    ВТ_Периоды.ДатаК,
    ВЫБОР
        КОГДА ВТ_Периоды.ДатаК < ВТ_Периоды.ДатаН
            ТОГДА 0
        ИНАЧЕ ГОД(ВТ_Периоды.ДатаК) - ГОД(ВТ_Периоды.ДатаН) - ВЫБОР
                КОГДА МЕСЯЦ(ВТ_Периоды.ДатаК) < МЕСЯЦ(ВТ_Периоды.ДатаН)
                    ТОГДА 1
                КОГДА МЕСЯЦ(ВТ_Периоды.ДатаК) > МЕСЯЦ(ВТ_Периоды.ДатаН)
                    ТОГДА 0
                ИНАЧЕ ВЫБОР
                        КОГДА ДЕНЬ(ВТ_Периоды.ДатаК) < ДЕНЬ(ВТ_Периоды.ДатаН)
                            ТОГДА 1
                        ИНАЧЕ 0
                    КОНЕЦ
            КОНЕЦ
    КОНЕЦ КАК Лет,
    ВЫБОР
        КОГДА ВТ_Периоды.ДатаК < ВТ_Периоды.ДатаН
            ТОГДА 0
        ИНАЧЕ ВЫБОР
                КОГДА МЕСЯЦ(ВТ_Периоды.ДатаК) > МЕСЯЦ(ВТ_Периоды.ДатаН)
                    ТОГДА 0
                КОГДА МЕСЯЦ(ВТ_Периоды.ДатаК) = МЕСЯЦ(ВТ_Периоды.ДатаН)
                        И ДЕНЬ(ВТ_Периоды.ДатаК) >= ДЕНЬ(ВТ_Периоды.ДатаН)
                    ТОГДА 0
                ИНАЧЕ 12
            КОНЕЦ + (МЕСЯЦ(ВТ_Периоды.ДатаК) - МЕСЯЦ(ВТ_Периоды.ДатаН)) - ВЫБОР
                КОГДА ДЕНЬ(ВТ_Периоды.ДатаК) < ДЕНЬ(ВТ_Периоды.ДатаН)
                    ТОГДА 1
                ИНАЧЕ 0
            КОНЕЦ
    КОНЕЦ КАК Месяцев,
    ВЫБОР
        КОГДА ВТ_Периоды.ДатаК < ВТ_Периоды.ДатаН
            ТОГДА 0
        ИНАЧЕ ВЫБОР
                КОГДА ДЕНЬ(ВТ_Периоды.ДатаК) >= ДЕНЬ(ВТ_Периоды.ДатаН)
                    ТОГДА ДЕНЬ(ВТ_Периоды.ДатаК) - ДЕНЬ(ВТ_Периоды.ДатаН) + 1
                ИНАЧЕ ДЕНЬ(КОНЕЦПЕРИОДА(ДОБАВИТЬКДАТЕ(ВТ_Периоды.ДатаК, МЕСЯЦ, -1), МЕСЯЦ)) - ДЕНЬ(ВТ_Периоды.ДатаН) + ДЕНЬ(ВТ_Периоды.ДатаК)
            КОНЕЦ
    КОНЕЦ КАК Дней
ИЗ
    ВТ_Периоды КАК ВТ_Периоды

Результат выглядит так:
ДатаН        ДатаК        Лет    Месяцев    Дней
21.09.2009    20.09.2010    0    11    30
21.09.2009    20.10.2010    1    0    29
21.09.2009    20.03.2010    0    5    27
21.09.2009    20.03.2012    2    5    28
20.10.2010    20.10.2010    0    0    1
20.10.2010    19.10.2010    0    0    0

Високосный год я учел. Разное количество в месяцах учел.
Что я не учел?
1 Said_We
 
20.07.18
02:32
Проверить расчет можно на онлайн калькуляторе.
Например на этом:
http://fincalculator.ru/kalkulyator-dnej

Суть примеров простая:
1. 21.09.2009    20.09.2010    0    11    30 - не хватает одного дня до полного года + расчет количества дней
2. 21.09.2009    20.10.2010    1    0    29, аналогично предыдущему примеру, только хватает на полный год + расчет количества дней отличается по результату, так как месяца разные.
3. 21.09.2009    20.03.2010    0    5    27 - НЕ високосный год
4. 21.09.2009    20.03.2012    2    5    28 - Високосный год
5. 20.10.2010    20.10.2010    0    0    1 - ДатаН = ДатаК
6. 20.10.2010    19.10.2010    0    0    0  - ДатаК < ДатаН, расчета нет, результат НОЛЬ.
2 VladZ
 
20.07.18
05:08
(0) ссылка кривая.
3 Said_We
 
20.07.18
09:39
Ну как перевернулась. Можно поиском.
4 Said_We
 
20.07.18
10:50
kb.mista.ru/article.php?id=664
5 Малыш Джон
 
20.07.18
10:54
количество дней можно покороче считать:
ВЫРАЗИТЬ(РАЗНОСТЬДАТ(Дата1,Дата2,СЕКУНДА)/86400 КАК Число(0))
6 Said_We
 
20.07.18
11:08
(5) Можно. Но логику проще видеть как я написал.
По поводу что быстрее работает не проверял. Но когда-то проверял, что РАЗНОСТЬДАТ и ДОБАВИТЬКДАТЕ работают обе не быстро. Никогда не смотрел ДЕНЬ - быстро или медленно не скажу.
7 Вафель
 
20.07.18
11:10
(6) те ты утверждаешь, что твоя конструкция работает быстрее чем РАЗНОСТЬДАТ ?
8 Said_We
 
20.07.18
11:13
(7) Не в коем случае. Я в сторону оптимизации по скорости даже не смотрел. И как раз в (6) я написал об этом.
9 Said_We
 
20.07.18
11:15
По ссылке в (4) длинный и сложный для понимания запрос.
Собственно вопрос в (0) - Чего я не учел?
Где результат будет отличаться?
10 Said_We
 
20.07.18
11:50
Тишина.....
11 Малыш Джон
 
20.07.18
11:52
Эммм... а ты какой реакции ждешь?
Усовершенствовал способ - ок, молодец.
А что ещё?
12 Said_We
 
20.07.18
12:08
Алгоритмы по объёму строк кода очень сильно отличаются. Собственно жду что где то может быть ошибка.
13 Said_We
 
20.07.18
13:04
(11) Статья в (0) (4) написана более 10 лет назад. Что там можно усовершенствовать?
14 Said_We
 
20.07.18
15:04
Пятница - всем лень смотреть видать.
15 Said_We
 
20.07.18
20:32
В общем не нужно это никому смотреть, анализировать, по всей видимости. Ну тогда будем считать, что работает как-то правильно.
16 EvgeniuXP
 
20.07.18
23:27
а можно сделать не как-то, а идеально точно :)
17 Said_We
 
21.07.18
14:14
(16) Найден недочет? Это здорово! Где?
18 Said_We
 
23.07.18
23:37
(16) пропал куда-то... :-(
19 hhhh
 
23.07.18
23:47
(18) ну философский вопрос решили? Сколько будет 28 февраля - 28 января?
20 Said_We
 
24.07.18
00:14
(19) Калькулятор в (1) сколько показывает? Думаю что месяц покажет. А между 29.01 и 28.02 покажет 30 дней. Так как месяц не полный. Важно же какой месяц.
21 hhhh
 
24.07.18
00:32
(20) ну получается парадокс вы не решили, у вас между 31 января и 28 февраля покажет неполный месяц.
22 Said_We
 
24.07.18
00:39
(19) В чем философия, когда необходимо посчитать количество лет, дней и месяцев между датами? Философия о количестве дней в месяце заканчивается ровно в тот момент, как появляется дата, для которой необходимо этот месяц определять.
А вот если надо стажи суммировать, то тут как раз есть философия. Что есть месяц и что с ним делать... А в (0) нет философии, тут арифметика.
23 Said_We
 
24.07.18
00:49
(21) Какой парадокс? Полный месяц между 28.01 И 28.02. Далее вы уменьшает период на день и хотите получить не полный месяц, а уменьшив ещё на день, получить опять полный? :-) При расчёте нет понятия конец месяца. Если от начала месяца до начала следующего месяца месяц, то это не означает, что от конца месяца до конца следующего, тоже месяц.
24 Said_We
 
24.07.18
13:30
(21) Собственно вопрос в (0) будут ли отличия в двух разных алгоритмах для расчёта одного и того же. Я пока разницы не нашёл. Может плохо искал. Взгляд со стороны всегда лучше.
25 Said_We
 
25.07.18
10:04
(21) Почему должно быть между 31.01 и 28.02 полный месяц?
28.01 - 28.02 - полный месяц.
29.01 - 28.02 - не полный месяц, уменьшили на один день период.
30.01 - 28.02 - не полный месяц, уменьшили на два дня период.
31.01 - 28.02 - не полный месяц, уменьшили на три дня период.

Если kb.mista.ru/article.php?id=664 дает другой результат, то это ошибка алгоритма.
26 Малыш Джон
 
25.07.18
10:07
(25) а почему 31.01-28.02 - это не полный месяц?(оба значения - конец дня разумеется)
27 Said_We
 
25.07.18
12:38
(26) А почему это должно быть полным месяцем?
При чем здесь конец это месяца или нет?
Если с 28.01 по 28.02 это полный месяц, с 29.01 по 28.02 уже не полный, то почему с 31.01 по 28.02 вдруг опять полный месяц? Где логика?
28 Малыш Джон
 
25.07.18
12:39
(27) ну про конец дня - это я для определенности)

тогда другой вопрос:

01.02  (00:00:00) - 28.02  (23:59:59) - это полный месяц?
29 Said_We
 
25.07.18
12:40
(26) Калькулятор в (1) тоже показывает с 31.01 по 28.02 не полный месяц, а 28 дней.
30 Said_We
 
25.07.18
12:41
(28) Нет. Полный месяц с 01.02 по 01.03.
31 Малыш Джон
 
25.07.18
12:46
Т.е. добавляем секунду в конец месяца (01.02 00:00:00 - 01.03 00:00:00) - это становится полный месяц, а добавляем секунду в начало месяца(31.01  23:59:59 - 28.02 23:59:59) -  - это не становится полным месяцем? Какая волшебная секунда...
32 Said_We
 
25.07.18
12:49
к (30) Если рассматривается период работы сотрудника с например 01.02.2018 по 28.02.2018 включительно, То передать в функцию необходимо с 01.02.2018 по 01.03.2018. Т.е. 01.03.2018 это дата не включается в период.
33 Said_We
 
25.07.18
12:51
(31) Секунды в данной функции не анализируются совсем....
34 Малыш Джон
 
25.07.18
13:05
(33) Бог с ними, с секундами

пример:

29.01 - 28.02 - неполный месяц

сдвигаем на день -

30.01 - 01.03 - полный месяц

Волшебный месяц март?
35 Said_We
 
25.07.18
13:22
(34) Между 30.01 и 01.03 Есть полный месяц февраль.
Что смущает?
36 sitex
 
naïve
25.07.18
13:27
(32) А почему не передаете конечную дату, как полную включительно т.е. 28-02-2018 23 59 59.  ?
37 Малыш Джон
 
25.07.18
13:28
(35) между 28.01 и 28.02 нет полного месяца февраля - а вот однако ж...
38 Said_We
 
25.07.18
13:35
Нашел я недочем в своем алгоритме. Не знаю почему другие ещё не нашли. В консоль наверное не загружали и не смотрели.

    ВЫБОР
        КОГДА ВТ_Периоды.ДатаК < ВТ_Периоды.ДатаН
            ТОГДА 0
        ИНАЧЕ ВЫБОР
                КОГДА ДЕНЬ(ВТ_Периоды.ДатаК) >= ДЕНЬ(ВТ_Периоды.ДатаН)
                    ТОГДА ДЕНЬ(ВТ_Периоды.ДатаК) - ДЕНЬ(ВТ_Периоды.ДатаН) + 1
                ИНАЧЕ ВЫБОР
                        КОГДА ДЕНЬ(КОНЕЦПЕРИОДА(ДОБАВИТЬКДАТЕ(ВТ_Периоды.ДатаК, МЕСЯЦ, -1), МЕСЯЦ)) < ДЕНЬ(ВТ_Периоды.ДатаН)
                            ТОГДА ДЕНЬ(ВТ_Периоды.ДатаК)
                        ИНАЧЕ ДЕНЬ(КОНЕЦПЕРИОДА(ДОБАВИТЬКДАТЕ(ВТ_Периоды.ДатаК, МЕСЯЦ, -1), МЕСЯЦ)) - ДЕНЬ(ВТ_Периоды.ДатаН) + ДЕНЬ(ВТ_Периоды.ДатаК)
                    КОНЕЦ
            КОНЕЦ
    КОНЕЦ КАК Дней
39 Said_We
 
25.07.18
13:37
(36) Это не принципиально как период рассматривать включительно или исключительно дата окончания. Можно и под включительно переписать, но мне не принципиально.
40 kumena
 
25.07.18
13:53
> Наткнулся на алгоритм расчета количества дней месяцев и лет между датами

ну что тут сказать, в ЗУП 2.5 с 2007 года, и он там уже был изначально в отчете списки сотрудников организаций.

наверное и в прошлых зупах тоже был.
41 kumena
 
25.07.18
14:01
+40 я имею ввиду запросом.
могу подкинуть еще более интересную задачку, сделай запросом, чтобы стажи не только между датами считались. т.е. при достижении в остатке после сложения всех стажей по строкам более 30 дней дни превращались в месяц (или несколько месяцев), при достижении в остатке после сложения всех стажей по строкам более 12 месяцев месяцы превращались в года.
и в итоге все стажи должны все сложиться в один, включая те что по дням и месяцам от сложения.
если что - у меня так сделано, можно посмотреть тут http://kumena.ru/products/zup-25-kalkulyator-stazha
42 Said_We
 
25.07.18
14:03
(40) Ну, что тут сказать. Работал с конфигурацией по расчёту ЗП в 1С8 с 2004 или 2005 года, но не ЗиУП. Потом совсем не работал с расчетными задачами. Тут случайно натолкнулся на алгоритм. Помню что алгоритм был на много проще. На вскидку вспомнил как примерно это было.
43 Said_We
 
25.07.18
14:08
(41) не видел на бумаге такого алгоритма. Были разные рекомендации и примеры расчёта, но противоречие друг лругу. Тут как раз как выше коллега заметил начинается философия. Год = 365 или 366 дня :-)
44 kumena
 
25.07.18
14:12
> не видел на бумаге такого алгоритма

а никто наверное алгоритм сложения стажей и не утверждал, все считают по своим правилам. хотя я сейчас даже не помню, может и на чем-то основывался, уже много лет прошло как это все делалось.
я вобщем-то просто задачу для развлечения предложил, раз свободное лишнее время есть.
45 kumena
 
25.07.18
14:14
собственно, когда я делал, тоже не загружен был, а потом через несколько лет он пригодился, когда именно срочно нужно было сделать свой показатель. и три дня никто бы ждать не стал.
46 Said_We
 
25.07.18
14:27
(44) Ну натолкнулся на этот алгоритм я тоже не от нечего делать :-)