Открыть список
Как стать автором
Обновить

Комментарии 49

Спасибо! А на C++/Qt что-то такое со временем есть — тоже приходилось костыли писать для монотонного непрерывного времени.

Конечно есть.
Если проект с C++11, то в chrono есть std::chrono::steady_clock. Если на более старом стандарте, то нужно использовать системные вызовы целевой ОС (вроде clock_gettime с CLOCK_MONOTONIC на *nix или QueryPerformanceCounter на винде).


К слову, все это легко находится в гугле по запросу "monotonic time c++/c++03/windows/unix".

Здорово, спасибо, мы писали ещё в 2010-2011, тогда этого стандарта ещё не было.
А boost::chrono уже был)
Возможно, а может не хотели лишнюю библиотеку в инсталлятор тащить.
Отличная статья, для некоторых вещей, реализованных в этих библиотеках, писались свои велосипеды.
Спасибо.
P.S. Вторая часть очень опосредованно относится к времени)

С неправильным временем у пользователя был занятный кейс. Мы делали некий продукт для небогатых, в основном, компаний, и он был сильно завязан на корректное время. Дело было в начале '10-ых, в России недавно переколбасили часовые пояса, а у всех была пиратская винда, которая не обновлялась и в ней не было новой tzdata. Приходилось брать время из ответов сервера, вводить поправку на сетевую задержку, вычислять смещение часового пояса и плясать с бубном, потому что в JS есть getTimezoneOffset, но нет setTimeZoneOffset...

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

А как брали поправку на сетевую задержку?

Уже не помню:( Как-то костыльненько, но погрешность нас устраивала.

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


Хочется, однако, риторически прокомментировать вот это :


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

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

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


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


И что характерно, авторы такого кода были всегда в почете (такой код можно писать быстро, перформанс наше все! — почти ж никто в ИТ не в курсе, что нужно перформанс для разрабов нужно переводить вторым главным значением — "эффективность", а не первым "производительность", интерпретируемую как скорость закрытия тасков на гора, а дальше не волнует).
Другое дело, что, как правило, авторы такого кода были уже далече, только не их попросили, а они на гребне волны славы сами успели уйти на повышение — в другие компании, реже в той же компании.

НЛО прилетело и опубликовало эту надпись здесь
«Перейти через шесть месяцев в другую команду» — это шутка, намёк на доклад с той же конференции об управлении командами разработчиков в большой компании. Прошу не воспринимать серьёзно и не принимать как руководство к действию.
И в других фреймворках с другими методами life cycle то же самое логично. Когда у вас происходит какой-то destruct, destroy, еще что-нибудь, unmount, надо корректно такие вещи не забывать чистить за собой.

А ещё можно использвать фреймворки, которые чистят всё автоматически, а не полагаются, что разработчик ничего не забудет..


слышали, хотя бы, про функциональный подход, про чистые функции, про отсутствие side-эффектов
эти два запроса асинхронных, они явно друг от друга не зависят

Вы бы хоть определение чистой функции почитали..


Изучайте качественный код, в том числе опенсорс — Lodash, RxJS и т. п.

https://github.com/lodash/lodash/blob/master/.internal/createRound.js
https://github.com/ReactiveX/rxjs/blob/master/src/internal/util/ArgumentOutOfRangeError.ts
Очень "качественный" код..

использвать фреймворки, которые чистят всё автоматически, а не полагаются, что разработчик ничего не забудет

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

$mol же. Реализовано просто — реактивные переменные отслеживают зависимости. Если значение ни кому не нужно — у него вызывается destructor. Пример.

А если я вызову обычный таймаут, то что?

Очевидно, ничего.

Ну то есть не работает оно в $mol. Тогда возвращаемся к предыдущему вопросу — а в каком фреймворке работает?

А вас кто-то заставляет вызывать setTimeout напрямую?

А в чём именно приведённый пример из лодаша некачественен?

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

А как бы вы это реализовали? Там 9 строк кода (если без скобок), думаю вам несложно будет показать лучшее решение, раз вы судя по всему его знаете
Со сравнением производительности
В идеале, конечно, сделать PR, но можно и просто здесь код показать
console.log(_.round(4.006, 2)); // 4.01
console.log(floor(4.006, 2)); // 4

console.log(_.round(4060, -2)); // 4100
console.log(floor(4060, -2)); // 4000



Вы точно проверяли свой код? Он работает неверно и не является заменой лодашевскому

Разные названия функций вас не смутили?

Не понял, то есть вы недовольны одним кодом, а привели пример переписывания другого?

Я не бросаюсь её защищать. Я прошу обосновать утверждение о том, что приведённый пример действительно плох.
Вы привели в пример функцию, которая используется в round. В floor тоже, да. Но ещё и в round. И если я правильно понял, вы хотели показать пример как переписать её "красиво". Естественно, не лишая её имеющейся функциональности
Может я не увидел чего-то по вашей ссылке, или не понял. Но мне показалось, что функциональности round в вашем коде нет. Прошу прощения, если не заметил, и ткните тогда пальцем в виде размещения этого кода здесь

НЛО прилетело и опубликовало эту надпись здесь

О каких именно фрагментах идёт речь?

А давайте вы самостоятельно замените floor на round в обеих реализациях и убедитесь, что ничего принципиально не изменится? Продолжать этот диалог мне не интересно, удачи вам по жизни.

Ещё непонятнее стало. Где ваш код round то? По вашей ссылке я вижу тот же "говнокод" со строками. Что на что вы предлагаете мне заменить?
Я допускаю, что не могу посмотреть ваш код, и вижу только код лодаша, потому что либо не разобрался в интерфейсе, либо в мобильном браузере что-то идёт не так. Но вы упорно отказываетесь показать свой код прямо здесь, и поэтому я до сих пор так и не увидел вашу красивую версию ф-ии round

Почему для Math.round() использованы строковые операции, описано комментарием прямо в исходнике — из-за не всегда верного округления Math.round. Например, попытка округления 1.005 до двух знаков после запятой "решением в лоб" Math.round(1.005 * 100) / 100 даст ровно 1, а _.round(1.005, 2) даст правильное значение 1.01.

  1. Эта "точность" никому не нужна ценой 10-кратного падения производительности.
  2. А те, кому нужна, не используют вещественные числа так как _.round( 1.00003+0.00002, 4 ) даёт всё ту же единицу.
Часто забывают, что месяцы в Date считаются с 0 и до 11.

Ошибаются в инкрементах на неделю, месяц, год в последних днях месяца. 31-01-2019 + 1 месяц = 31-02-2019 = 03-03-2019. Иногда забывают про високосные годы.

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

Отдельная тема — часовые пояса. Какой сейчас день? А где именно? Вот уж действительно начинаешь понимать, что живёшь в пространственно-временном континууме. Чтобы определить «когда» нужно знать «во сколько» и «где». Хранить информацию о времени в unix timestamp может быть не лучшей идеей. Нужно сто раз взвесить, прежде чем решать приводить все к UTC.

На самом деле, не имея информации о часовом поясе и актуальной версии tzdata вы мало, что можете правильно посчитать. Рассчет на сервере и на клиенте может давать разные результаты. После очередного апдейта tzdata результаты могут сильно измениться.

Так же хлопот доставляют форматы записи дат в разных локалях. 10/11/12 без контекста не распарить.
Про даты я бы добавил про таймзону. Особенно весело когда на фрон приходит дата в timestamp и может показать каку, если таймзона на беке оказалась не та

Но ведь обычно timestamp это количество (милли) секунд, прошедших с конкретного момента времени. Для него нет таймзоны. Где бы я ни находился, в Сеуле или в Лондоне, количество секунд будет одинаково

Просто часто удобно задавать дату не в виде timestamp, а как строку — '09-02-2020'. Пример апи гугл анатилики. Важно чтобы не было рассинхрона таймзоны. Если у нас локальная таймзона Сеул, а в апи на беке таймзона — Москва. Тогда на бек дата должна прийти с учётом таймзоны. И если у нас нет нигде рассинхрона в таймзоне, значит мы распарсим дату в timestamp, запишем в БД его. И при обраотке в бд и последующем извлечении и отдаче куда-либо — у нас всё будет хорошо.
Когда дата приходит строкой без таймзоны это повод задуматься в любом случае. Либо имеется в виду gmt, либо важен только сам день (возможно само время), не важно в каком часовом поясе. А вообще желательно всегда использовать iso 8601
Но вы писали
на фрон приходит дата в timestamp… если таймзона на беке оказалась не та
— я только это и хотел отметить. У timestamp нет часового пояса

Странно что не упомянуты еще типичные грабли:


  1. Запрос в БД с указанием ТОЛЬКО дат диапазона, когда в поле в БД включает еще и время. Типично от получается в запросе поле времени по умолчанию 00:00:00 до 00:00:00, а нужно, как правило, от 00:00:00 до 23:59:59. Очень типичная ошибка.


  2. Запрос из браузера выборки по диапазону времени. А времени чего? От TZ браузера? От TZ БД? От Гринвича/MSK? А вообще чего нужно то? Полночь в России наступает в разное время.



Кстати, типично, что в большинстве протоколов "нарисованных" разработчиками из Москвы отсутствует таймзона как сущность воооообще.
А на вопрос "а в какой TZ время то указывать?" вызывает ступор. Как будто другой TZ кроме MSK не бывает и не важно где (TZ) по факту событие произошло. Особенно не важно это для фродмониторинга <сарказм>


Особенно весело, когда встает вопрос про отчеты для банка у которого филиалы и в Москве и Владивостоке и слияние недавно произошло. Вопрос не технический. Организационный.


И по моему мнению, больше всего проблем с TZ возникает.
Например в таком простом вопросе "Хочу видеть транзакции за вчера. Филиалы у нас в Барнауле, Москве и Владивостоке, а терминалы по всей России".


А вам слабо объяснить сотруднику в Барнауле, почему список транзакций за день у него и сотрудника в Москве разный при одном подходе (список исходя из TZ браузера оператора).
Или почему он не видит транзакцию сделанную сегодня ночью (вот же она на чеке) в списке транзакций за сутки при другом подходе (список, исходя из TZ головного филиала в Москве).
И начинается… ваш софт г-но и выдает ерунду. "Хотим кнопку счастья для любого тупого сотрудника."


Иногда кажется что у многих абстрактное мышление отсутствует как класс..

поле времени… нужно, как правило, от 00:00:00 до 23:59:59

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


Например, если время хранится с точностью до миллисекунды, то надо задавать диапазон времени от 00:00:00 до 23:59:59.999


Как вариант, чтобы меньше вспоминать о точности хранения времени, можно задавать конечную дату в запросе как "меньше 00:00:00 следующего дня", а не "меньше или равно 23:59:59.999 текущего дня".

Эволюционно пришли к тому же выводу, иначе от базы к базе нужно каждый раз помнить как там дата и время храниться. Проще делать в WHERE условие datetime < '2019-08-13 00:00:00' чем выяснять про секунды и миллисекунды
Мне тут приходилось объяснять заказчику почему задача сохранения времени пользователя на сервере и построение отчетности в сервисе, расчитаным на весь мир, может занять много времени. А потом ещё разработчикам объяснять, почему мы будем хранить время в UTC, со сдвигом пользователя от UTC. Все (и заказчик, и разработчики) были в смятении, и смотрели на меня как на сказочника. Покажу им эту статью. Это я еще про летнее/зимнее время забыл, блин… Спасибо, что напомнили.
Рекомендую еще по теме.

Это с .Net конфы, но именно про .Net там вторая часть выступления, а в первой части докладчик просто очень интересно и стеконезависимо рассказывает про часовые пояса и базы с их описаниями, типы календарей, нюансы отсчета временных отрезков и баги из истории, связанные со всем этим.
Какое-то невнятное выступление на видео. В тексте лучше описано
Не то, чтобы я зануда, но зачем упомянута Java в тегах и списке хабов?
Если уж упомянули ее, было бы неплохо кратко хотя бы пробежаться по особенностям и фичам при работе с временем/календарем. Уж до 8й версии там было о чем рассказать, это точно. А это до сих пор больше половины всех проектов. А может и больше.
Микрософт не парится и в своих логах пишет локальное время, которая скачет при синхронизации с NTP и изменении таймзоны.
Можно было бы конечно реализовать временные отметки не в абсолютном времени, а в относительно, типа сколько времени прошло от старта большого процесса.
Но часто удобнее просто поискать по локальному времени, чем искать начало и считать смещение.

Есть ещё такая экзотическая штука как "высокосная секунда". Встречается нечасто и мало кому мешает. Но мне как-то изрядно выпила крови при синхронизации времени двух телецентров.

Про время — старое но не потерявшее актуальности видео. www.youtube.com/watch?v=-5wpm-gesOY С ним всё очень, очень грустно… Особенно, когда вспоминаешь, на что из списка натыкался
Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.

Информация

Дата основания
Местоположение
Россия
Сайт
www.yandex.ru
Численность
свыше 10 000 человек
Дата регистрации

Блог на Хабре