Имя: Пароль:
1C
1С v8
Ближайшая дата рождения (задачка на программирование)
0 дущ
 
16.12.16
01:28
Встала задача определить ближайшее день рождения у произвольного человека. Ближайшее не только будущее, но и прошедшее. То есть, определить что ближе: прошлое или будущее день рождения.

Написал вот такой вот ужас

    ДеньРожденияВЭтомГоду    = ДобавитьМесяц(НачалоГода(Дата), Месяц(рКарта.ДеньРождения) - 1) + (День(рКарта.ДеньРождения) - 1) * 86400;
    ДеньРожденияВПрошломГоду= ДобавитьМесяц(НачалоГода(ДобавитьМесяц(Дата, - 12)), Месяц(рКарта.ДеньРождения) - 1) + (День(рКарта.ДеньРождения) - 1) * 86400;
    ДеньРожденияВСледующемГоду= ДобавитьМесяц(НачалоГода(ДобавитьМесяц(Дата, + 12)), Месяц(рКарта.ДеньРождения) - 1) + (День(рКарта.ДеньРождения) - 1) * 86400;
    РазницаВЭтомГоду    = (Дата - ДеньРожденияВЭтомГоду);
    РазницаВЭтомГоду    = Макс(РазницаВЭтомГоду, - РазницаВЭтомГоду);
    РазницаВПрошломГоду    = (Дата - ДеньРожденияВПрошломГоду);
    РазницаВПрошломГоду    = Макс(РазницаВПрошломГоду, - РазницаВПрошломГоду);
    РазницаВСледующемГоду    = (Дата - ДеньРожденияВСледующемГоду);
    РазницаВСледующемГоду    = Макс(РазницаВСледующемГоду, - РазницаВСледующемГоду);
    Если РазницаВЭтомГоду > РазницаВПрошломГоду Тогда
        Если РазницаВПрошломГоду > РазницаВСледующемГоду Тогда
            ДеньРождения    = ДеньРожденияВСледующемГоду;
        Иначе
            ДеньРождения    = ДеньРожденияВПрошломГоду;
        КонецЕсли;
    Иначе
        Если РазницаВЭтомГоду > РазницаВСледующемГоду Тогда
            ДеньРождения    = ДеньРожденияВСледующемГоду;
        Иначе
            ДеньРождения    = ДеньРожденияВЭтомГоду;
        КонецЕсли;
    КонецЕсли;


где Дата - текущая дата, а рКарта.ДеньРождения - дата, когда родился клиент. Вкратце, нахожу три даты ближайшие дни рождения человека (например, родился 13.03.1980, я нахожу 13.03.2015, 13.03.2016 и 13.03.2017, среди них точно будет ближайшее день рождения), и ищу минимальную разницу между этими датами и сегодняшним днем.
Получается очень сложно, долго, длинно, непонятно.
Печенкой чую, есть изящнее решение. Может кто-то найдет и приведёт?
1 Torquader
 
16.12.16
01:36
Расстояние между двумя датами - это от большей отнять меньшую - после того как будет таблица, можно по ней взять минимум.
И что тут сложного ?
2 Torquader
 
16.12.16
01:37
Проблема только с теми, кто родился 29 февраля - не очень понятно, что считать меньшей, а что большей датой дня рождения.
3 дущ
 
16.12.16
01:46
Задача в том, что бы найти это как можно проще.
4 Zhuravlik
 
16.12.16
01:48
(0) ДатаРождения = Дата(1980, 3, 21);

ДеньДаты = День(ДатаРождения);
МесяцДаты = Месяц(ДатаРождения);

ТекДата = НачалоДня(ТекущаяДата());

НомерТекущегоГода = Год(ТекущаяДата());

ДатаРожденияВТекущемГоду = Дата(НомерТекущегоГода, МесяцДаты, ДеньДаты);
ДатаРожденияВПрошломГоду = Дата(НомерТекущегоГода - 1, МесяцДаты, ДеньДаты);    
ДатаРожденияВБудущемГоду = Дата(НомерТекущегоГода + 1, МесяцДаты, ДеньДаты);

СоответствиеИнтервалДата = Новый Соответствие;
инт_Прошлый = ДатаРожденияВПрошломГоду - ТекДата; СоответствиеИнтервалДата.Вставить(инт_Прошлый, ДатаРожденияВПрошломГоду); инт_Прошлый = Макс(инт_Прошлый, -инт_Прошлый);
инт_Текущий = ДатаРожденияВТекущемГоду - ТекДата; СоответствиеИнтервалДата.Вставить(инт_Текущий, ДатаРожденияВТекущемГоду); инт_Текущий = Макс(инт_Текущий, -инт_Текущий);
инт_Будущий = ДатаРожденияВБудущемГоду - ТекДата; СоответствиеИнтервалДата.Вставить(инт_Будущий, ДатаРожденияВБудущемГоду); инт_Будущий = Макс(инт_Будущий, -инт_Будущий);

НаименьшийИнтервал = Мин(инт_Прошлый, инт_Текущий, инт_Будущий);

ДатаРожденияБлижайшая = СоответствиеИнтервалДата.Получить(НаименьшийИнтервал);
Если ДатаРожденияБлижайшая = Неопределено Тогда
    ДатаРожденияБлижайшая = СоответствиеИнтервалДата.Получить(-НаименьшийИнтервал);
КонецЕсли;

Осталось понять что с (2) делать)
5 Torquader
 
16.12.16
02:13
На самом деле, у нас есть таблица: ИдЧеловека,ДеньРождения,МесяцРождения

лтзДниРождения - таблица значений

Функция мфПолучитьБлижайшийДеньРождения(птзДниРожденияСотрудников)
лтзБлижайшиеДаты=Новый ТаблицаЗначений;
лтзБлижайшиеДаты.Колонки.Добавить("Человек");
лтзБлижайшиеДаты.Колонки.Добавить("ДеньРождения");
лтзБлижайшиеДаты.Колонки.Добавить("Разница");

лчТекущаяДата=НачалоДня(ТекущаяДата());
лчТекущийГод=ДатаГод(лчТекущаяДата);

Для Каждого лстзДеньРождения Из птзДниРожденияСотрудников Цикл
лчДень=лстзДеньРождения.ДеньРождения;
лчМесяц=лстзДеньРождения.МесяцРождения;
Если(лчДень=29)И(лчМесяц=2)Тогда
  лстзБлижайшаяДата=лтзБлижайшиеДаты.Добавить();
  лстзБлижайшаяДата.Человек=лстзДеньРождения.ИдЧеловека;
  лстзБлижайшаяДата.ДеньРождения=Дата(лчТекущийГод-1,2,28,0,0,0)+86400;
  лстзБлижайшаяДата.Разница=лчТекущаяДата-лстзБлижайшаяДата.ДеньРождения;
  лстзБлижайшаяДата=лтзБлижайшиеДаты.Добавить();
  лстзБлижайшаяДата.Человек=лстзДеньРождения.ИдЧеловека;
  лстзБлижайшаяДата.ДеньРождения=Дата(лчТекущийГод,2,28,0,0,0)+86400;
  лчРазница=лчТекущаяДата-лстзБлижайшаяДата.ДеньРождения;
  Если лчРазница<0 Тогда
   лстзБлижайшаяДата.Разница=-лчРазница;
  Иначе
   лстзБлижайшаяДата.Разница=лчРазница;
  КонецЕсли;
  лстзБлижайшаяДата=лтзБлижайшиеДаты.Добавить();
  лстзБлижайшаяДата.Человек=лстзДеньРождения.ИдЧеловека;
  лстзБлижайшаяДата.ДеньРождения=Дата(лчТекущийГод+1,2,28,0,0,0)+86400;
  лстзБлижайшаяДата.Разница=лстзБлижайшаяДата.ДеньРождения-лчТекущаяДата;
Иначе
  лстзБлижайшаяДата=лтзБлижайшиеДаты.Добавить();
  лстзБлижайшаяДата.Человек=лстзДеньРождения.ИдЧеловека;
  лстзБлижайшаяДата.ДеньРождения=Дата(лчТекущийГод-1,лчМесяц,лчДень,0,0,0);
  лстзБлижайшаяДата.Разница=лчТекущаяДата-лстзБлижайшаяДата.ДеньРождения;
  лстзБлижайшаяДата=лтзБлижайшиеДаты.Добавить();
  лстзБлижайшаяДата.Человек=лстзДеньРождения.ИдЧеловека;
  лстзБлижайшаяДата.ДеньРождения=Дата(лчТекущийГод,лчМесяц,лчДень,0,0,0);
  лчРазница=лчТекущаяДата-лстзБлижайшаяДата.ДеньРождения;
  Если лчРазница<0 Тогда
   лстзБлижайшаяДата.Разница=-лчРазница;
  Иначе
   лстзБлижайшаяДата.Разница=лчРазница;
  КонецЕсли;
  лстзБлижайшаяДата=лтзБлижайшиеДаты.Добавить();
  лстзБлижайшаяДата.Человек=лстзДеньРождения.ИдЧеловека;
  лстзБлижайшаяДата.ДеньРождения=Дата(лчТекущийГод+1,лчМесяц,лчДень,0,0,0);
  лстзБлижайшаяДата.Разница=лстзБлижайшаяДата.ДеньРождения-лчТекущаяДата;
КонецЕсли;
КонецЦикла;
лтзБлижайшиеДаты.Сортировать("Разница Возр");
Если лтзБлижайшиеДаты.Количество()=0 Тогда
Возврат НЕОПРЕДЕЛЕНО;
КонецЕсли;
лстзТекущийДеньРождения=лтзБлижайшиеДаты[0];
Возврат Новый Структура("Человек,ДеньРождения",лстзТекущийДеньРождения.Человек,лстзТекущийДеньРождения.ДеньРождения);
КонецФункции
6 SeraFim
 
16.12.16
03:20
1. Определяем КоличествоПолныхЛет
2. Прибавляем к дате рождения КоличествоПолныхЛет и КоличествоПолныхЛет+1.
3. ищем, какая из этих 2 дат ближе к текущей дате

Плюсы подобного подхода:
- Никаких проблем с 29 февраля.
- Выбирать придется из 2 дат, а не 3
7 SeraFim
 
16.12.16
03:24
+ (6) предвижу вопросы - а как считать КоличествоПолныхЛет? Вот стандартный типовой способ для запроса - можно переделать в обычный код :)

    ГОД(&Период) - ГОД(РаботникиОрганизации.Сотрудник.Физлицо.ДатаРождения) + ВЫБОР
        КОГДА МЕСЯЦ(РаботникиОрганизации.Сотрудник.Физлицо.ДатаРождения) * 100 + ДЕНЬ(РаботникиОрганизации.Сотрудник.Физлицо.ДатаРождения) > МЕСЯЦ(&Период) * 100 + ДЕНЬ(&Период)
            ТОГДА -1
        ИНАЧЕ 0
    КОНЕЦ
8 Mort
 
16.12.16
07:40
ДатаРождения = '08.05.1982';
ТекущаяДата = ТекущаяДата();

Результат = ДатаРождения;
СледующийГод = Дата(Год(Результат) + 1, Месяц(Результат), День(Результат));

Пока Макс(ТекущаяДата - Результат, Результат - ТекущаяДата) > Макс(ТекущаяДата - СледующийГод, СледующийГод - ТекущаяДата) Цикл
   Результат = СледующийГод;
   СледующийГод = Дата(Год(Результат) + 1, Месяц(Результат), День(Результат));
КонецЦикла;

Сообщить(Результат);
9 xxTANATORxx
 
16.12.16
09:31
(0)ИМХО одним запросом делается
есчо лень писать
10 SSSSS_AAAAA
 
16.12.16
09:47
" ближайшее день "
День - он, потому "ближайшИЙ".
11 Кирпич
 
16.12.16
10:06
(10) у нас на районе не звонЯт, а звОнят
12 rabbidX
 
16.12.16
10:16
Если МесяцТекущейДаты >=7 Тогда ПосчитатьИСравнитьРазницуВЭтомИБудущемГоду(...);
Иначе
ПосчитатьИСравнитьРазницуВЭтомИПрошломГоду (...);
КонецЕсли;
13 rabbidX
 
16.12.16
10:20
Если МесяцДатыРождения >= 7 Тогда
НеСчитатьРазницуСБудущимГодом = Истина;
Иначе
НеСчитатьРазницуСПрошлымГодом = Истина;
КонецЕсли;
14 Вафель
 
16.12.16
10:20
сначала привести все даты к 0 году, потом обычная задача на минимум
15 Азазелло
 
18.12.16
20:28
(0) ДеньГода
Д1 = ДеньГода(ДатаДР);
Д2 = ДеньГода(ТекущаяДата());

А ближайшее ДР будет через Макс(0, Д1 - Д2) дней
16 Азазелло
 
18.12.16
20:29
+(15) будет или было, в зависимости от знака Д1 - Д2
17 Euguln
 
18.12.16
20:34
(9) + 1. РАЗНОСТЬДАТ И МИНИМУМ.
18 Vaflya
 
18.12.16
20:56
Запросом запросто
19 Лефмихалыч
 
18.12.16
21:01
(0) и правда ужас. Там тупое соединение на больше-меньше и минимум-максимум.
20 Vaflya
 
18.12.16
21:22
(19) та ну, видится выбор когда разница между тек.дата и будущий др больше разницы между тек.датой и прошедшим др.тогда прошедший
21 Vaflya
 
18.12.16
21:24
Всмысле даже соединений не нужно
22 MetaDon
 
18.12.16
21:25
да = РазницаДат()>183 дня ;
Основная теорема систематики: Новые системы плодят новые проблемы.