«O tempora, o mores!»

Для протокола: заголовок я позаимствовал у Цицерона, в Oratio in Catilinam Prima in Senatu Habita.


Cicero Denounces Catiline, fresco by Cesare Maccari, 1882–1888




В реальной жизни мы часто имеем дело с временны́ми интервалами. Свиданки с зубным врачом, бронирование гостиничных номеров, даже ежедневный обеденный перерыв: планирование всего этого — задача подгонки временно́го интервала в ряд других временны́х интервалов.


Допустим, нам пора навестить стоматолога. Я знаю, что мне нужен 1 час для ежегодной плановой проверки. Я могу посетить врача во время обеда или после работы. У доктора есть и другие пациенты. На диаграмме ниже мои рабочие часы показаны фиолетовым цветом, докторские — красным, нерабочие — серым, а счастливо найденный слот, когда мы оба свободны, — зеленым.


Timelines of my busy hours and the dentist’s busy hours


Беглого взгляда на эту диаграмму достаточно, чтобы определить время назначенной встречи. Завтра, в обеденное время. Легко, да?


К сожалению, ни один из известных мне языков программирования не предоставляет возможности определить это программно. Последние несколько лет я состою в тесных отношениях с эликсиром, поэтому пришлось написать библиотеку, решающую именно эту проблему.


Итак, встречайте Tempus!


Детали реализации


Сущность, вокруг которой построена вся библиотека — Slot. Он представляет временной интервал самым естественным и простым способом: это структура, с полями from и to, оба типа DateTime. Набор слотов хранится в структуре Slots, под капотом реализованной как AVLTree. Этот выбор был сделан для того, чтобы сохранить базовый список слотов согласованным (упорядоченным и не перекрывающимся) с наименьшими затратами при оптимизации доступа по чтению и записи. Обычно список слотов заполняется при инициализации и потом используется для проверки, поиска свободных интервалов, и тому подобного.


Функция Slots.add/2 добавит в список слотов — новый, объединяя слоты по мере необходимости. Это позволяет просто вставлять новые слоты в конструкцию, не беспокоясь о порядке и перекрытии. Также предусмотрена вспомогательная функция Slots.merge/2 для объединения двух наборов слотов. Последнее особенно удобно, когда нужно, например, найти пустой слот в обеих сериях, как в примере с выбором времени посещения дантиста выше.


Можно также проверить любое время на предмет занятости при помощи функций их модуля Slot: покрывает ли слот заданное время (или другой слот), являются ли слоты непересекающимися, или нет и т. д.


Модуль Tempus


Основной модуль экспортирует функции для работы со слотами, как с прерывистой временной шкалой. Можно добавить любой произвольный интервал времени к началу координат, принимая во внимание слоты; проверить, свободен ли этот интервал, или уже занят слотами, получить следующий свободный или следующий занятый слот, инвертировать временную шкалу, и многое другое.


Вот незамысловатый пример из тестов:


slots =
  [
    Tempus.Slot.wrap(~D|2020-08-07|), # whole day
    %Tempus.Slot{
      from: ~U|2020-08-08 01:01:00Z|, # one minute
      to: ~U|2020-08-08 01:02:00Z|
    },
    %Tempus.Slot{
      from: ~U|2020-08-08 01:03:00Z|, # one minute
      to: ~U|2020-08-08 01:04:00Z|
    }
  ]
  |> Enum.into(%Tempus.Slots{})

Если добавить 0 секунд ко времени, уже занятому слотом, вернется первое доступное время после занятого промежутка.


Tempus.add(slots, ~U|2020-08-08 01:01:30Z|, 0, :second)
#⇒ ~U[2020-08-08 01:02:00Z]

Добавив 70 секунд ко времени, на пять секунд предшествующему первому занятому слоту — ~U[2020-08-08 01:00:55Z] — вернется экземпляр DateTime через пять секунд после второго занятого слота (5sec + занято + 60sec + занято + 5sec):


Tempus.add(slots, ~U|2020-08-08 01:00:55Z|, 70, :second)
#⇒ ~U[2020-08-08 01:04:05Z]

И так далее. Разумеется, можно добавлять и отрицательные значения.


Слияние наборов слотов


Slots.merge/2 понимает Stream в качестве второго аргумента. На данный момент библиотека не поддерживает слияние и использование двух потоков слотов, но вливание потока в существующие временные интервалы возможно. Это может быть полезно, когда у нас есть короткий список, скажем, праздников, и мы хотим объединить его с повторяющимися слотами, например с выходными.


Все функции, возвращающие Slots и / или Slot — гарантированно отдают допустимые объекты (нормализованные, упорядоченные и объединенные по мере необходимости).


Что еще?


Текущая реализация покрывает только наши внутренние потребности, поэтому я был бы рад услышать о том, чего не хватает этой библиотеке и что следует в нее добавить.




Удачных временных интервалов!

Ads
AdBlock has stolen the banner, but banners are not teeth — they will be back

More

Comments 42

    +2
    А что, TZ у вас одна на все события, во всех последовательностях?

    И еще — зачастую события и интервалы бывают повторяющимися, правда, я не вижу особо, что это может поменять, потому что описанные задачи обычно решаются на ограниченном интервале, от силы год, и можно повторения за год раскрыть в отдельные события/интервалы.

    Ну и еще у того, что вы называете слотами, бывают свойства — произвольные. Если описать это в ваших же терминах, то у доктора могут быть не просто пациенты, а известное число пациентов, поэтому свойство интервала у доктора — это именно число. И если оно скажем 2 и менее — вас примут, а если 3 — то нет. В вашем варианте занятость доктора — это просто наличие слота на временной шкале.

    Совершенно не факт, что все это стоит добавлять, но посмотреть можно на любую библиотеку с поддержкой формата iCal например, и прикинуть, что они умеют. Да и импорт-экспорт iCal наверное не помешает.
      –1
      TZ у вас одна на все события

      TZ это атрибут инстанса DateTime, очевидно. Вот сниппет из продакшн-кода, отвечающий за стрим слотов, когда fx-markets закрыты, с корректной обработкой DST, между прочим:


          first_weekend = %Slot{
            from: DateTime.from_naive!(
                ~N|2018-01-05 21:00:00|,
                "America/New_York"),
            to: DateTime.from_naive!(
                ~N|2018-01-08 08:59:59|,
                "Australia/Sydney")
          }
      
          weekends =
            Stream.iterate(
              first_weekend,
              fn acc ->
                acc
                |> Tempus.Slot.shift(from: @μs_in_week, to: @μs_in_week)
                |> Tempus.Slot.shift_tz()
              end
            )

      события и интервалы бывают повторяющимися

      Вот выше пример, там повторяющиеся события. Stream же.


      у того, что вы называете слотами, бывают свойства — произвольные

      Да, это, кажется, очень разумное рац. предложение, внедрю, когда выдастся свободное время, спасибо!


      посмотреть можно на любую библиотеку с поддержкой формата iCal например, и прикинуть, что они умеют

      Я решал практическую задачу, а не писал сферическую библиотеку в вакууме. Но, да, посмотрю, спасибо за наводку.


      импорт-экспорт iCal наверное не помешает

      Наверное, да, посмотрю тоже, спасибо.

        +1
        Сферическую это не про iCal — просто это же в принципе обычный типовой календарь, а их часто рисуют где-то в аутлуке. Ну и и экспорт самый удобный в iCal, поэтому его поддержка это просто тупо удобно. Хотя сам формат — на мой взгляд типично дурацкий.

        Ну и на библиотеки я и имел в виду посмотреть — но не обязательно реализовывать все то, что они умеют.

        >Вот выше пример, там повторяющиеся события. Stream же.
        Понял. Просто без знания синтаксиса это было не очевидно.

        Что до TZ — то тут скорее вопрос в том, где вы берете их описание (и как обновляется их база). А уж если даты в прошлом (особенно далеко в прошлом) — то и подавно не очевидно, где брать описание зон.

        Вообще, решить для произвольной даты, America/New_York и -5 — это одно и тоже, или же нет, не всегда тривиально. А уж если интервал захватывает какой-то переход на летнее время — то и подавно (потому что на концах интервала время может плавать на час туда-сюда, и по-идее, похожий на вид интервал в разных зонах может оказаться разной длины).
          +1
          Сразу вспомнилось вот это видео :)

            +1
            Если бы я мог не работать… :) к сожалению, у нас в некоторых базах бывают даже даты 1 января 0 года (до нашей эры к счастью не встречались). И проблем с ними, прямо скажем, дофига — потому что когда в процессе завязаны скажем БД Оракл (разных версий), MS SQL (тоже разные), Oracle Golden Gate (или OGG BDA). Java, Spark, Hive, Impala, и т.п., и добиться чтобы все это работало согласованно, да еще и с единой базой зон — это практически недостижимо.
            0
            где вы берете их описание (и как обновляется их база)

            В Unicode Consortium’s Common Locale Data Repository, а где еще? Обновляется каждый день.


            похожий на вид интервал в разных зонах может оказаться разной длины

            Это на себя берет DateTime из поставки эликсира с правильным календарем (Cldr). Туда можно хоть еврейский календарь засунуть, и все будет работать.


            если интервал захватывает какой-то переход на летнее время — то и подавно

            dt = DateTime.from_naive!(~N|2020-11-01 00:00:00|, "America/New_York")
            #⇒ #DateTime<2020-11-01 00:00:00-04:00 EDT America/New_York>
            DateTime.add(dt, 3600, :second).hour
            #⇒ 1
            DateTime.add(dt, 7200, :second).hour
            #⇒ 1

            Внутри я добавляю микросекунды, так что тут все чисто.

              +1
              >Внутри я добавляю микросекунды, так что тут все чисто.
              Я про другое — интервал в одной зоне может в другой просто не существовать, потому что перевод на летнее/зимнее время иногда выглядит так: у нас было 0 часов вчера, а потом сразу бац — и час ночи сегодня. Все что между нулем и часом — в этой зоне не существует. При этом, насколько я понимаю, тут могут вылезать разные странные случаи при любой обработке такого кейса.

              >Это на себя берет DateTime из поставки эликсира с правильным календарем (Cldr).
              Тут не очень понятно, что значит «правильный», если в разных календарях 00:05 либо является валидным временем, а в другом календаре это же время не существует? Оба календаря по своему правильные — но друг с другом они конфликтуют.

              Не факт что это существенно для любой системы, но у нас вот вылезает время от времени. Скорее всего, если вы планируете визит к стоматологу, вы на такое никогда не наступите. Но если стоматолог в другой зоне свой календарь ведет — то могут быть разные странности.
                0
                если в разных календарях 00:05 либо является валидным временем, а в другом календаре это же время не существует

                Я не понимаю, где тут возможна проблема. Добавить слот с таким временем не позволит Slots.add/2. Slot.valid?/1 вернет false, потому что время не валидно.


                Tempus.add/4, как я показал выше, отработает корректно. Никаких конфликтов календарей нет, они диффеоморфны. Функция преобразования одного в другой — задана реализацией календаря.


                если стоматолог в другой зоне свой календарь ведет

                Я выше же опубликовал пример вот ровно для этого случая. Fx-рынки открываются в понедельник в 9:00 в Сиднее и закрываются в 22:00 в пятницу в Нью-Йорке. По местному времени, да. DST в этих городах вообще не согласовано никак.



                И мой код прекрасно с этим справляется; это была почти ключевая задача этой библиотеки (помимо просто планирования переговорок): стрим добавляет по 86400 секунд к понедельнику, 8 утра по Сиднею и пятнице, 10 вечера, по Нью-Йорку. А потом переводит получившиеся значения в UTC для дальнейших операций. Разница между from и to плавает в пределах двух часов, в зависимости от времени года.


                Надо будет этот момент поподробнее разжевать в документации, а то мои коллеги тоже не поверили, что все так радужно :)

                  0
                  >Я не понимаю, где тут возможна проблема.
                  >Добавить слот с таким временем не позволит Slots.add/2. Slot.valid?/1 вернет false, потому что время не валидно.
                  Что значит не валидно, когда оно валидно (в другом календаре)? Ну смотрите, это по Москве, какого-то марта непонятного года, когда был переход на летнее время не было интервала времени с 0 до часу ночи. Но в другом календаре это время вполне валидно. Ну или в наших терминах, как у меня в проекте — Оракл DB считает, что эти вот 05 минут первого вполне правильное время (потому что у него оно например в UTC), а Java на нашей стороне — уже нет (потому что мы пытаемся преобразовать его в MSK, например), и корректирует его на 01:00.

                  Я не говорю что с этим ничего сделать нельзя, просто поведение в таком случае вполне может быть неожиданным с точки зрения юзера где-то в UI. Я даже не исключаю, что к вашей библиотеке это вообще отношения не имеет, но проблема такая есть, и вполне реальная.
                    0
                    Что значит не валидно, когда оно валидно (в другом календаре)?

                    Календарь — атрибут инстанса DateTime. Время без календаря называется NaiveDateTime и в принципе не имеет смысла в расчетах с вовлечением разных временны́х зон.


                    Java на нашей стороне — уже нет (потому что мы пытаемся преобразовать его в MSK, например)

                    Это шутка? Совершенно очевидно, что любое время в UTC можно конвертировать в любую другую таймзону, включая MSK. Это напрямую следует из непрерывности временной координаты пространства-времени. То, что ваш код не справляется с тем, чтобы сделать это правильно — не вина времени, Оракла, или Java.


                    поведение в таком случае вполне может быть неожиданным с точки зрения юзера где-то в UI

                    Не может. Пользователю нужно все показывать в какой-то одной таймзоне. Обычно это либо его локальное время, либо локальное время сервера, либо UTC. Вытащите хоть стопятьсот времен из разных источников (обязательное условие: они должны все идти в комплекте с таймзоной, иначе да, проблемы), сконвертируйте во время пользователя, и обпоказывайтесь. Никаких сюрпризов там быть не может.

                      +1
                      >Это шутка? Совершенно очевидно, что любое время в UTC можно конвертировать в любую другую таймзону, включая MSK. Это напрямую следует из непрерывности временной координаты пространства-времени.
                      Нет, это совершенно не шутка. Нет никакой непрерывности. Переход на летнее время осуществляется как я написал ранее — после 0 часов следует сразу 1 час ночи. Скажем так — в некоторых системах это так работает. Если вы такого не видели — не значит что так не бывает.
                        –1
                        Если вы такого не видели — не значит что так не бывает.

                        Я на DST собаку съел, и видел буквально всё. Я знаю, как осуществляется переход на летнее время. Повторяю еще раз: время непрерывно (это физический факт, его нелепо оспаривать). То, что какие-то соглашения между какими-то людьми изменили систему координат и способ записи — на само время не влияет ровным счетом никак.


                        0:30 MSK в базе оказаться не может, если код писал не криворукий дебил. Время в UTC (и любой другой зоне), переведенное в MSK, внезапно оказаться 0:30 MSK не может. Такому времени неоткуда взяться.


                        Если кто-то хранит время без зоны, а потом цепляет к нему MSK и удивляется — этого человека имеет смысл уволить вчерашним днем.


                        Как я показал в примере выше, мой код с входными данными 23:30 MSK + minutes(31) в этот конкретный день — вернет 1:01 MSK. Если вы продолжаете считать, что там есть какие-то сложности — я предлагаю еще раз подумать, найти все места, где время хранится без таймзон, и переписать все правильно.


                        Еще раз, для закрепления:


                        dt = DateTime.from_naive!(~N|2020-11-01 00:00:00|, "America/New_York")
                        #⇒ #DateTime<2020-11-01 00:00:00-04:00 EDT America/New_York>
                        DateTime.add(dt, 3600, :second)     
                        #⇒ #DateTime<2020-11-01 01:00:00-04:00 EDT America/New_York>
                        DateTime.add(dt, 7200, :second)     
                        #⇒ #DateTime<2020-11-01 01:00:00-05:00 EST America/New_York>
                          0
                          >0:30 MSK в базе оказаться не может, если код писал не криворукий дебил. Время в UTC (и любой другой зоне), переведенное в MSK, внезапно оказаться 0:30 MSK не может. Такому времени неоткуда взяться.

                          Вы не поняли. Оно не оказывается 0:30. Оно преобразуется в ближайшее валидное. Именно это и является для пользователей неприятным сюрпризом.
                            0

                            Если честно, я и правда уже мало, что понимаю.


                            Для пользователя оказывается сюрпризом, что ему показывают правильное время вместо несуществующего?

                              0
                              > Условно 20:59 utc это 23:59 msk, 21:00 utc это 0:00 msk, а 21:01 utc это 01:01 msk.

                              Ну вот смотрите. alexzeed ниже привел пример, как это должно выглядеть с его точки зрения. Я согласен, что это выглядит логично. Но проблема в том, что в реальности это бывает не 01:01, а ближайшее валидное время, то есть скажем 01:00. И минуты при этом пропадают. И обратно в UTC это уже не сконвертировать без потерь.

                              Если кто-то хранит время без зоны, а потом цепляет к нему MSK и удивляется — этого человека имеет смысл уволить вчерашним днем.


                              Он все-таки видимо не совсем так делает, хотя близко к этому. Но главное эффект такой как я выше описал. А уволить при этом придется слишком многих, потому что у нас например, эта проблема всплывает во взаимодействии Oracle DB, Oracle Golden Gate, Java, Hive.
                                0
                                Но проблема в том, что в реальности это бывает не 01:01, а ближайшее валидное время, то есть скажем 01:00. И минуты при этом пропадают. И обратно в UTC это уже не сконвертировать без потерь.

                                Да вы издеваетесь, что ли?


                                Куда пропадают минуты? С какого, простите, хрена, они куда-то пропадают?


                                Я не имел дел с ораклом и джавой уже почти 20 лет, но и тогда, 20 лет назад, ни один их этих монстров не стал бы отсекать минуты во времени без прямого на то указания.


                                Ваша проблема связана с некомпетентностью разработчиков, работающих с временами в вашей этой связке. В мире, где люди умеют обращаться с таймзонами, а не просто пишут код на авось, такой проблемы не существует.


                                Ее нет, так же, как нет проблемы деления на ноль. На ноль не делят, а если делят, то получают фигню — и обвинять в этом ноль — по меньшей мере странно. И alexzeed все изложил предельно корректно и верно.

                                  0
                                  >Куда пропадают минуты? С какого, простите, хрена, они куда-то пропадают?

                                  Объясняю на пальцах — если Java парсеру из строк в даты подсунуть вот такую невалидную дату (т.е. 00:05, с таймзоной, само собой) — то она преобразуется в ближайшую валидную. Всех деталей я уже не помню, но в целом поведение было именно такое. И я вас уверяю, оно документированное — т.е. это такая фича. Почему так? ХЗ, я могу только предположить. Ведь java дата — это по сути просто число миллисекунд от начала времен, и с переходом на летнее время в таком представлении всегда проблемы будут, потому что берете вы число миллисекунд в 00:00, прибавляете скажем 30 секунд — и получить вы должны не 00:30, а час ночи.

                                  Ваша проблема связана с некомпетентностью разработчиков, работающих с временами в вашей этой связке.


                                  Ну, с большой вероятностью это разработчики Golden Gate — потому что а) невалидная дата в виде строки приходит именно от них б) у них были и другие баги с временными зонами. И я бы охотно последовал вашему совету их уволить — но увы, ни одной вменяемой альтернативы OGG в природе не существует, поэтому с их багами приходится мириться.
                                    +2

                                    Я человек неленивый. Стандартный парсер в более-менее нормальном языке программирования таким детским недугом страдать не может. Он и не страдает, что характерно.


                                    https://repl.it/repls/IntelligentSpottedDowngrade


                                    Ввод:


                                    import java.text.ParseException;
                                    import java.text.SimpleDateFormat;
                                    import java.util.Date;
                                    
                                    class Main {
                                      public static void main(String[] args) {
                                        try {
                                          String input = "Sun Mar 08 02:30:00 EDT 2020";
                                          SimpleDateFormat parser = new SimpleDateFormat("EEE MMM d HH:mm:ss zzz yyyy");
                                          Date date = parser.parse(input);
                                          String formattedDate = parser.format(date);
                                    
                                          System.out.println(formattedDate);
                                        } catch (ParseException pe) {
                                          System.out.println("Oooups");
                                        }
                                      }
                                    }

                                    Вывод:


                                    $ javac -classpath .:/run_dir/junit-4.12.jar:target/dependency/* -d . Main.java
                                    $ java -classpath .:/run_dir/junit-4.12.jar:target/dependency/* Main
                                    //⇒ Sun Mar 8 01:30:00 EST 2020
                                      –1
                                      А что, 8 марта 2020 в этой зоне переход на летнее время?

                                      То что вы показываете — не единственный «стандартный» парсер, потому что у нас Java 8, и там есть и другие. И не единственный возможный режим парсинга. Ну и главное — у вас время на выходе уменьшается, т.е. из 02:30 получается 01:30, а это не наш случай. У нас переход в обратную сторону, когда 00:00 становится 01:00.

                                      >Я не имел дел с ораклом и джавой уже почти 20 лет
                                      А я с ними каждый день имею дело. И у меня примерно 100 или чуть больше разных ораклов, и штук 20 MS SQL. Я вполне понимаю ваше возмущение на тему «ну не может же там быть такой фигни», но уж поверьте — может. Вот прямо так сразу все детали не вспомню, но если любопытно — завтра постараюсь найти.
                                        +2
                                        Ну и главное — у вас время на выходе уменьшается, т.е. из 02:30 получается 01:30, а это не наш случай.

                                        Я опроверг ложный тезис о том, что время округляется. Вы бы хоть немного за ходом дискуссии послеживали, а?


                                        Между двумя и тремя часами ночи в этот день в этой таймзоне происходит перевод стрелок вперед. Времени 2:30, таким образом, не существует. И никто никуда никого не округляет, но корректно переводит в зимнее время, потому что 3:00 еще не наступило. Когда наступит, перевод осуществится в летнее время. Корректно. Без округлений и смс.


                                        Проще этого парсера нет, и быть не может, но давайте, озвучьте, каким пользуетесь вы — и я в том же репле покажу, что с джавой все в порядке. Даже с шестой.


                                        alexzeed не понимаю, что вас удивляет в вашем же примере и зачем вы обзываете авторов джавы. Время никуда не округляется, время корректируется, причем корректируется правильно. Там нет никакого UB, представьте себе рулетку с выкушенным куском 10см-20см. Если вы станете отмерять 15см — увидите 25см, и это правильно. Разумно, и ожидаемо.


                                        Вы запросили 03:30 EET, вам вернули 04:30 EEST. На зону обратите внимание тоже.

                                          –1
                                          >Я опроверг ложный тезис
                                          Какой еще тезис? Посмотрите ответ alexzeed ниже. Более того, о том, что оно округляется — это только вы и говорите, поэтому непонятно, чего тут нужно было опровергать?

                                          Я такое слово «округляется» не употреблял, alexzeed тоже. Я говорил, что оно становится ближайшим валидным — то есть в моем случае часом. Приведенная ниже цитата из документации это полностью подтверждает.

                                          Разница между вашим примером и нашим реальным видимо может состоять в том, что в реальном таймзона задана через setTimeZone у SimpleDateFormat, либо по-умолчанию (что в общем почти одно и тоже). Хотя как мы видим ниже, в таком варианте оно тоже проявляется.

                                          И еще ваш пример отличается тем, что у вас две разные зоны для зимнего и летнего времени, EST и EDT. У нас же зона ровно одна, московская. Это как минимум другой случай.
                                            0
                                            проблема в том, что в реальности это бывает не 01:01, а ближайшее валидное время, то есть скажем 01:00. И минуты при этом пропадают. И обратно в UTC это уже не сконвертировать без потерь.

                                            Я говорил, что оно становится ближайшим валидным — то есть в моем случае часом. Приведенная ниже цитата из документации это полностью подтверждает.

                                            Вообще никак не подтверждает. Мне надоело, если честно, с вами спорить, потому что вы либо вообще не понимаете, о чем говорите, либо готовы на любую казуистику, лишь бы замять глупость, которую высказали ранее.


                                            «Становится ближайшим валидным» и «округляет» — это одно и то же, вообще-то. Минуты, разумеется, никуда не пропадают. А приведенная цитата говорит о том, что время правильно сдвигается в правильную сторону.

                                              0
                                              Знаете, почему у вас карма -14, при том что вы достаточно умный? Потому что вы самоуверены до безобразия. Я не собирался вам ничего доказывать. Вы не работали ни с ораклом ни с Java 20 лет — но все еще уверены, что все о них знаете. Вы написали 1 тест — и решили, что все доказали. Ступайте мимо.
                                                0
                                                Знаете, почему у вас карма -14, при том что вы достаточно умный?

                                                Конечно. Потому что я не стесняюсь указывать людям недостаточно умным на то, что они недостаточно умные. Я ценю отрицательную карму на этом ресурсе, она мне льстит.


                                                Ступайте мимо.

                                                Так-то это вы приперлись в комментарии к моему тексту с неверными замечаниями, так что ступайте-ка сами.

                                                  0

                                                  Ad hominem.

                                                    0
                                                    Вовсе нет. Во-первых, я предпочитаю вариант «Разве нас может интересовать мнение человека лысого и вот с таким носом». А во-вторых, это просто мнение об авторе, без попытки что-либо доказать. Без хамства, причем. Он считает меня недостаточно умным, а я его. Ну и норм.
                                                      0

                                                      Это тоже аргумент к человеку.


                                                      Вам довольно долго объясняли с иллюстрациями, чем представление отличается от сущности, вы даже в какой-то момент изобразили понимание. Но потом пошли на очередной круг.

                                                        0
                                                        Знаете, почему у вас карма -14, при том что вы достаточно умный?
                                                        Он считает меня недостаточно умным, а я его. Ну и норм.

                                                        Ловко вы прям на лету переобуваетесь. Ну ничего, на хабре это любят. И ад хоминем любят, если он против кого надо ад хоминем.

                                  +3

                                  А мне тоже непонятна проблема с 0:30. Условно 20:59 utc это 23:59 msk, 21:00 utc это 0:00 msk, а 21:01 utc это 01:01 msk. И все. Не может быть 0:30 msk в этот день, неоткуда ему взяться, если кто-то при парсинге 0:30 мск вместо эксепшена превращает его молча в 01:00, то он нехороший редиска, но время тут ни причем.

                                    0
                                    Я вас уверяю, этот нехороший человек — это кто-то из авторов java рантайма. То есть, такое происходит, если вы парсите дату в нормальном формате, с зоной, совершенно стандартным механизмом. Конкретных деталей не приведу — во-первых, это было года полтора назад, а во-вторых, я тот тест не писал, а только читал. Но если интересно, могу в понедельник поискать, без гарантии успеха.
                                      +2
                                      Приношу свои извинения, был самоуверен. Мнение, что авторы джава рантайма нехорошие редиски, не изменю :) И не только из-за этого момента с некорректным временем. Мой опыт разработки на джаве лет 7, но именно с парсингом локального времени не сталкивался. Да, оказывается при парсинге времени, которое попадает в дырку перехода на летнее прибавляется 1 час:
                                      new SimpleDateFormat("dd.MM.yyyy HH:mm zzz").parse("29.03.2020 03:30 EET").toString()
                                      дает "Sun Mar 29 04:30:00 EEST 2020". Для SimpleDateFormat в доке не нашел, а для ZonedDateTime этот ноговыстрел действительно задокументирован (класс ZonedDateTime: For Gaps, the general strategy is that if the local date-time falls in the middle of a Gap, then the resulting zoned date-time will have a local date-time shifted forwards by the length of the Gap, resulting in a date-time in the later offset, typically «summer» time). Остаюсь при мнении что тут должен эксепшен выскочить вместо хитрых коррекций.
                                      Вообще, мне это напрминает обработку ситуаций Undefined Behavior в С++. Типа, «такого не должно быть, поэтому делаем что хотим».
                                      Ну и такая штука не должна возникать при работе с базой. Она должна возникать на уровне ввода пользовательских данных, или с UI, или допустим из какого-то CSV файла, в общем — снаружи системы. А внутри все времена должны представляться в каком-то непрерывном формате, тогда таких приколов не будет.
                                        0
                                        >Приношу свои извинения, был самоуверен.
                                        Да ладно, мы вполне культурно пообщались, без негатива. Тем более всем интересно, и пример вы в конечном счете самостоятельно раскопали. Вы с chapuza явно оба неленивые, любите докопаться до истины :)

                                        Я ведь в общем и не спорил, что такое поведение — оно не совсем явное, и было бы неплохо либо выкинуть исключение, либо что-то еще сделать, чтобы было понятно, что такое вот произошло. Но факт что оно вполне описано, и тут уж не особо пожалуешься.

                                        Самое смешное, что мы докопались до поддержки оракла, но они тогда ответили что-то совсем невменяемое, типа поменяйте локальную таймзону на UTC, или что-то в этом духе.

                                        >Ну и такая штука не должна возникать при работе с базой.
                                        Ну как-бы на стыке OGG и Hive — это примерно и есть снаружи. И на csv воспроизводилось. То есть, вы в csv кладете такую вот дату, говорите Hive, что этот файл есть таблица вот такой структуры — и опа, в таблице уже часы поменялись.

                                        Опять же, не должна — это в идеальном мире :) В нашем реальном оракл позволяет хранить в базе невалидные даты. То есть польностью невалидные, отрицательные компоненты, а также 61 минуту, 25 часов и пр. И хуже всего, что некоторые разработчики, как у нас выражаются, «с фантазией», этим вот всем пользуются. Хорошо что редко :)
                  0
                  >разумное рац. предложение, внедрю, когда выдастся свободное время, спасибо!
                  Ну да, этож позволяет отмечать интервал не бинарным свойством свободен/занят, а скажем «я тут буду читать книжку, но в принципе для встреч свободен».
                –2

                А чем это отличается от диаграмм Ганта?

                  +3
                  Э, всем? Это вообще не они. Тут речь про шкалы времени, и отрезки на них, графа тут может и не быть, и задачи решаются другие — приведенная задача со стоматологом это типовой пример планирования митинга — есть шкалы свободного и занятого времени участников, включая комнату для переговоров. И надо их всех совместить, чтобы все участники могли, и комната была свободна.
                  +2
                  К сожалению, ни один из известных мне языков программирования не предоставляет возможности определить это программно.

                  Может я что-то не понимаю, можете попробовать изучить SQL, — вроде как это стандартная задача из не очень сложных. К примеру, у вас таблица начал и окончаний интервалов занятости лиц и параметром задано значение длительности встречи. Вам надо выбрать все окончания занятости лица 1 (врача), для которых,
                  — его самое близкое сверху начало занятости будет отстоять вверх на величину большую длительности встречи;
                  — самое близкое сверху к нему начало интервала занятости лица 2 (вы) будет также отстоять вверх на величину большую длительности встречи и посередине не будет окончания занятости лица 2.
                    0
                    можете попробовать изучить SQL

                    Спасибо, откажусь. Я его еще не настолько забыл, чтобы изучать заново.


                    К примеру, у вас таблица [...]

                    К примеру, у меня вообще нет базы данных.


                    Вам надо выбрать все окончания занятости [...]

                    Не только. Например, мне нужно добавить 5 ×​ 31_557_600 секунд к сегодняшней дате, игнорируя специально заданные «праздники» и все выходные (в моем решении задается стримом). И получить точное значение DateTime, с учетом таймзоны в Сиднее, Австралия.


                    Или мне нужно объединить занятые слоты дантиста с государственными праздниками Каталонии.


                    Или мне нужно выбрать первый после первого января 2037 года слот продолжительностью в один час, в который свободны все вот эти 10 человек, комната, канал связи, и который пересекается с рабочим временем в таймзоне America/New_York.

                      0
                      К примеру, у вас таблица
                      К примеру, у меня вообще нет базы данных.

                      Наверное таки есть у вас база данных, хоть и самопальная. Данные ведь как-то храните и каким-то образом же обрабатываете.

                      Не только. Например, мне нужно добавить 5 ×​ 31_557_600 секунд к сегодняшней дате, игнорируя специально заданные «праздники» и все выходные (в моем решении задается стримом). И получить точное значение DateTime, с учетом таймзоны в Сиднее, Австралия.

                      Или мне нужно объединить занятые слоты дантиста с государственными праздниками Каталонии.

                      Или мне нужно выбрать первый после первого января 2037 года слот продолжительностью в один час, в который свободны все вот эти 10 человек, комната, канал связи, и который пересекается с рабочим временем в таймзоне America/New_York.

                      ¡No passaran, camarada! Российский Крым приветствует свободную реcпублику Каталония! Возвращаясь к SQL, вы всерьез полагаете (dangling participle), что упомянутые вами нюансы запросов недоступны для SQL. Поправьте меня, если я не прав, но я привык думать, что любой SQL-related джун вам с легкостью отчебучит и не такое.
                        0
                        Данные ведь как-то храните и каким-то образом же обрабатываете.

                        Нет, не храню. Это микросервис, который отвечает по API на запросы. Весь in-memory.

                    0
                    Подскажите, пожалуйста, почему у меня может не работать ссылка:
                    «Итак, встречайте Tempus!»

                    Комп обычный, другие сайты работают… В каких настройках мне надо порыться?

                    Я лет 25 назад сделал свою библиотеку для работы с календарными интервалами для научных расчетов (она до сих пор используется). Но — на фортране. Одно время было желание как-то превратить этот проект в Open Source, но недостаток мозгов и отсутствие вменяемого английского не позволили сделать даже первый шаг в эту сторону :-((( А сейчас уже и смысла нет, очевидно.
                    Но посмотреть функционал Вашей библиотеки хочется. Хотя бы для того, чтобы добавить в свой пакет что-то полезное.
                    0
                    извиняюсь, что просмотрел по диагонали, но учтена возможность смены времени зимнее/летнее внутри интервала?

                    Only users with full accounts can post comments. Log in, please.