Я так смешно разочарован необходимостью использовать значения DateTime для наборов данных, которые действительно "всего лишь день". Дни рождения - самый распространенный пример, но это постоянно встречается в бизнес-приложениях.
Я привык просто устанавливать для части времени записей «только для даты» значение «полдень» (что позволяет избежать изменения даты независимо от часового пояса). Это похоже на хак, и я навсегда нахожу ошибки от младших разработчиков, которые спотыкаются об этой проблеме.
Время всегда относительно фиксированной точки. 4 вечера - 4 часа после меридиана или полдень. Наблюдается самая высокая точка Солнца в пути, что позволяет нам установить систему координат. За 3 часа до полудня (Анте Меридиан), через 2 часа после полудня, 1441899402938 миллисекунд с 1 января 1970 года. Для людей, выросших в декартовом мире, это вторая натура.
Но наш календарь предшествует Декарту. Мой аргумент состоит в том, что он более правильно воспринимается как перечисление, к которому применяется функция по модулю. Понедельник следует за воскресеньем и так далее, пока вы не дойдете до того факта, что воскресенье следует за субботой. Здесь нет положительного и отрицательного, это модуль или абсолютное значение.
Аналогично с повторением лет. Каждые 365 дней (или около того) у меня есть несколько особых дней: дни рождения, юбилеи, дни рождения детей и т. Д. мы МОЖЕМ отобразить это на число с плавающей запятой, и, по правде говоря, отображение его на указанное число решает ОЧЕНЬ много проблем, которые действительно сложны по-старому, но это не значит, что это единственный способ сделать это.
Понимание и понимание природы «квадратного колышка в круглой дыре» использования DateTimes для хранения дат делает, по моему мнению, лучшим программистом.
Есть ли смысл в приложении, явно предназначенном для планирования, при определении класса Date или «лучший способ установить полдень»? Какие проблемы могут возникнуть при использовании DateTime и установке компонента Time в полдень? Можно ли учитывать изменение часового пояса при таком подходе? Я использовал MomentJS, но я думаю, что это просто лучший класс Date.
источник
Ответы:
Прежде всего, давайте уберем одну вещь: дни рождения - это одно, даты рождения - другое. День рождения экзотический тип данных , поскольку в нем отсутствует не только компоненты часов, минут и т.д. , но это также не хватает год компонента. Если вы действительно хотите иметь дело с днями рождения, я бы порекомендовал придумать собственный тип данных, который содержит только номер месяца и номер дня и не связан ни с одним из встроенных типов данных дата-время.
С другой стороны, если вы хотите также отслеживать год рождения, то у вас есть не дни рождения, а даты рождения . Итак, теперь возникает вопрос, почему нет типа данных только для даты, чтобы вы могли удобно представлять даты рождения, и вместо этого популярные языки, кажется, заставляют вас использовать какой-то тип, который также включает компонент времени.
Позвольте мне кратко упомянуть, что это неправда, что все языки программирования предлагают только временные типы данных, которые включают компонент времени. Я встречал типы данных только для дат в СУБД и на соответствующих им диалектах SQL. Но это не имеет значения: тот факт, что эти типы данных существуют, не означает, что они полезны, и СУБД имеют долгую историю путаницы хранения с представлением.
Вы поймете, почему плохая идея иметь такие типы данных только для даты, как только вы поймете, что время является координатой. Большинство людей имеют очень смутное представление о том, что такое время, и эта идея содержит загадочные культурные понятия, такие как годы, месяцы и дни, не осознавая, что эти понятия носят исключительно репрезентативный характер : они полезны только для представления времени человеку и получения время как вход от человека. На любом слое ниже фактического элемента управления GUI с вводом времени время должно быть и обычно представляется в виде временной координаты, которая представляет собой единое число единиц времени с момента возникновения.
Например, в
DateTime
типе данных Microsoft Dotnet единица времени составляет 100 наносекунд, а начало времени - 12:00 ночи, 1 января, 0001 г.Другим примером тайной, исключительно репрезентативной записи являются измерения углов с использованием градусов, минут градуса и секунд градуса. Конечно, для выполнения каких-либо полезных вычислений вы должны использовать радианы для внутреннего использования и, если необходимо, преобразовывать градусы в градусы и обратно при взаимодействии с пользователем-человеком.
Таким образом, не путайте удобочитаемое представление измерения с фактическим характером измерения. Довольно часто идеальный метод для осуществления измерения, который наиболее близко соответствует природе измерения, очень отличается от воспринимаемого человеком представления этого измерения.
В свете всего этого ваш запрос временного типа данных, который представляет только даты, похож на запрос углового типа данных, который мог бы представлять только градусы, явно не допуская большей точности. Такой тип данных будет весьма ограниченным и в конечном итоге бесполезным, потому что вам все равно придется преобразовывать его в радианы и обратно, чтобы с ним можно было что-нибудь полезное сделать.
Ваша проблема с датой рождения заключается в том, что у вас неточная временная координата: человек, конечно, родился в определенный момент времени, но часы и минуты либо не были записаны в больнице, либо мы не заботиться о них. Итак, на самом деле происходит то, что ваша координата времени даты и времени рождения имеет предел погрешности, допустимого отклонения или неопределенности, если хотите, и лучше всего рассматривать это так: ставьте точно посередине и рассмотрим подразумеваемую погрешность +12 -12 часов. И это именно то решение, к которому вы интуитивно пришли.
источник
Даты и время - это много разных вещей в зависимости от контекста, и вам нужно много отдельных типов, чтобы охватить все варианты использования.
DateTime
Типа присутствует во многих языках представляют собой точную точку во времени ( «мгновенное время»). Помимо этого у нас есть ряд относительных или «человеческих» концепций времени и времени, таких как календарные дни, повторяющиеся даты, месяцы, годы и т. Д., Которые во многих случаях неоднозначны и зависят от контекста. Эти типы не так универсально полезны, но необходимы в определенных областях приложений, таких как календари, инструменты планирования и другие приложения, которые взаимодействуют с человеческими представлениями о времени.Если вы пишете что-то наподобие календарного приложения, вы определенно выиграете от использования библиотеки, такой как Joda-time, которая предоставляет более богатый набор типов времени. Например
LocalDate
, дата без времени. Это имеет семантику, отличную от обычнойDateTime
с временной частью, установленной на ноль, так как по-DateTime
прежнему указывает конкретный момент времени (полночь в определенном часовом поясе), в то время какLocalDate
указывает на весь день и не привязан к конкретному часовому поясу. Это также означает, что вы не можете напрямую перевести одно на другое.LocalDate
конечно проще чемDateTime
потому, что не нужно принимать во внимание часовые пояса, но вы должны знать о других проблемах, например, о том, что текущая дата может фактически измениться, когда вы пересекаете часовой пояс, и что тот же самый момент времени может соответствуют разным датам в разных часовых поясах. Если вы используете локальные даты в сетевых или веб-приложениях, вы должны быть очень осторожны с этими проблемами. Удаление временной части из даты не решает фундаментальную проблему часовых поясов! И если принять во внимание исторические даты и различные культуры, это станет еще сложнее, поскольку одна и та же дата может соответствовать совершенно разным моментам времени, скажем, в юлианском и григорианском календарях.Теперь вы спрашиваете, почему у языков нет чего-то подобного
LocalDate
встроенному . Ну, во-первых, некоторые языки, такие как SQL и Visual Basic, имеют тип даты без временной части. И Java также добавилиLocalDate
в недавней версии. Но других платформ, таких как .Net нет. Только разработчики языка могут действительно ответить, почему это не включено в стандартную библиотеку, но я предполагаю, что «мгновенное время» концептуально просто и универсально полезно, в то время как другие понятия времени полезны только для конкретных областей применения (таких как календари и т. Д.). .). Поэтому имеет смысл позволить разработчику приложения написать собственные типы для обработки более сложных вариантов использования или разрешить его обработку сторонней библиотекой (например, Joda-time).источник
Вероятно, это связано с тем, что календарь сложен и используется так по-разному, что никто не смог изобразить класс, который является простым, но достаточно общим, чтобы быть полезным во многих областях.
Тип даты, обычно встречающийся в языках программирования, может использоваться для точного определения даты транзакций в компьютерной системе. Другие варианты использования, вероятно, потребуют пользовательской библиотеки.
Вот краткие списки фактов о календарях, демонстрирующие их сложность - большинство из них являются историческими, поэтому, если вы ограничите свое внимание датами после 1.1.1970, это вас не затронет. Однако, если ваше приложение должно работать с датами, произошедшими до конца 19-го века, тогда эти факты будут иметь значение. Возможными вариантами использования являются исторические базы данных всех видов (книги, генеалогия), а также активы крупных компаний или организаций, которые все еще действуют сегодня.
Все эти факты процитированы из превосходного FAQ, найденного в календарной библиотеке для OCaml, написанной Жюльеном Синьоль.
Юлианский календарь был введен Юлием Цезарем в 45 году до нашей эры. Он использовался до 1500-х годов, когда страны начали переходить на григорианский календарь (раздел 2.2). Однако некоторые страны (например, Греция и Россия) использовали его в 1900-х годах, и православная церковь в России все еще использует его, как и некоторые другие православные церкви.
Переход от юлианского к григорианскому календарю происходил неравномерно, и в зависимости от года изменения было упущено от 10 до 13 дней. Например, во Франции 9 декабря 1582 г. последовало 20 декабря 1582 г., а в Греции 9 марта 1924 г. - 23 марта 1924 г.
Даже в современную эпоху много разных календарей (григорианский, православный, исламский и китайский) используются для цитирования нескольких, которые используют разные способы подсчета лет и годовщин или даты религиозных праздников.
Теперь вы надеетесь на тип даты, связанный с операциями, полезными для общих бизнес-операций. Я предполагаю, что нет такой вещи как общие деловые операции. Например, в мире финансов нам нужно вычислить:
Доли в годах (например, «6 месяцев» соответствуют «0,5»), которые используются в сочетании с процентной ставкой для расчета фактической процентной ставки по кредиту за определенный срок. Существует 6–10 рецептов для вычисления этих фракций, каждый из которых отличается по способам обработки продолжительности високосного года, позиции периода относительно последнего дня февраля и продолжительности месяца.
Сдвигая дату, при вычислении годовщин мы используем бизнес-календарь и правило (выбранное из набора из более чем 6 различных правил), чтобы перевести годовщину с праздника на рабочий день.
Для людей, работающих в финансовой сфере, любой тип календаря, не реализующий все эти функции и правила, бесполезен. Вполне вероятно, что многие другие отрасли имеют другие типы привычек и соглашений, требующих пользовательских вычислений в календаре.
Если вам нужно отслеживать один календарный день, возможно, лучше всего использовать большое целое число, представляющее юлианский день этого календарного дня. Алгоритмы преобразования назад и вперед из юлианского дня в календарный день, описанные с помощью года, месяца и календаря, широко известны и тщательно протестированы, чтобы вы могли легко реализовать их в своем приложении и выяснить, какое правило уместно в вашем случай для вычисления годовщины события, произошедшего 29 февраля.
источник
Я думаю, что Майк Накис в своем ответе выше лучше объясняет, как время в целом является абсолютной измеренной координатой, а любая другая связь, предполагаемое состояние или постоянство этой временной координаты - просто абстрактное представление указанной временной координаты.
Вы говорите с такими представлениями, когда называете День недели просто модульным представлением фактического момента времени. На самом деле это несколько сложнее, чем это. Если вам было поручено написать функцию, которая будет возвращать день недели для данного момента времени, рассмотрите следующую информацию, которая вам понадобится в качестве входных данных для такого алгоритма. Вам потребуется момент времени, календарь, часовой пояс, который необходимо учитывать (имейте в виду, что часовые пояса меняются ВСЕ ВРЕМЯ, поэтому вам нужно знать, когда этот эффективный часовой пояс начал существовать, когда он заканчивался в определенных временных координатах. Недавно Северная Корея просто например, изменили их!), и если действует летнее время, оно также меняется со временем. Теперь рассмотрим, если вам дали DateTime в местном часовом поясе,
Вы можете видеть, насколько сложным может казаться этот на первый взгляд простой вопрос.
Я знаю, какую боль вы испытываете, когда я был на вашем месте, когда-то исправлял все ошибки в приложении для планирования посещений для продукта, написанного неопытными разработчиками. Все это нужно было списать.
Время действительно является координатой, но помимо простой даты, рассмотрим другие чувствительные ко времени данные, которые могут понадобиться, например:
Длительность: промежуток в миллисекундах, который может произойти, что означает длительность или протекание времени без указания конкретных временных координат. Вариант использования может быть,
Интервал: интервал времени между двумя конкретными временными координатами. Случай использования, когда вы можете рассмотреть интервал.
Еще одно быстрое замечание, которое я хотел сделать, это то, что вы сделали комментарий о числах с плавающей запятой для данных, основанных на времени, и я советую против этого. Арифметика с плавающей точкой неизбежно приводит к ошибкам округления, которые могут не дать вам настолько точного измерения, сколько необходимо для времени.
Итак, в заключение, вся эта информация неизбежно приводит к следующим соображениям дизайна:
источник
Короче говоря, потому что большинство типов времени, основанных на компьютерах, сосредоточены на правильной обработке проблемы времени и часового пояса.
Есть 2 крайних случая, которые не поддаются обычному подходу. Установка момента времени, который находится на другой стороне перехода на летнее время, с использованием местного времени, которое затем преобразуется в UTC более низким уровнем абстракции, а затем на 1 час раньше или позже для вашей встречи.
Другой (в соответствии с вопросом) моделирует произвольную информацию о дате, такую как запись даты рождения человека. Представьте себе случай, когда два человека родились одновременно, один в Новой Зеландии, другой на Гавайях. Вероятно, что в их паспортах будут разные даты рождения, и если человек, родившийся на Гавайях, переедет в Новую Зеландию, он будет считаться на день старше, чем человек, родившийся в Новой Зеландии, несмотря на то, что он прожил в то же время.
Предложение в вопросе, как установить дату, чтобы иметь время полудня, UTC будет работать, ПОЧТИ везде. Смещения UTC варьируются от -12 до +14, поэтому в Тихом океане есть несколько мест, где этот подход потерпит неудачу. Я склонен относиться к этим типам данных как к строкам в формате ггггммдд, и если мне нужно сравнить вычисления между двумя датами, это можно безопасно сделать как сравнение строк. При выполнении дельта-сравнений (например, между датой и временем или продолжительностью до достижения возраста X) необходимо убедиться, что все даты созданы с одним и тем же смещением UTC, а затем использовать стандартные функции времени для выполнения работы.
источник
Date
тип данных, просто переносимый в аString
По тем же причинам, я думаю, что значения DateTime обычно указываются в UTC: простота и надежность . Смысл значения DateTime состоит в том, чтобы указать один момент времени, на который не влияют часовой пояс, летнее время, календарь и другие локальные настройки. Значения DateTime указывают одно мгновение (до ограничения разрешения типа), а не период времени или набор времени. Эти ограничения позволяют сравнивать значения DateTime надежным, предсказуемым, несложным способом.
Попытка указать дату со значением DateTime аналогична попытке использовать точку для указания области.Вы можете выполнить эту работу, используя соглашение, например, «эта точка представляет центр круга с радиусом 100 м», но там много проблем: всем нужно использовать одно и то же соглашение, вам нужно написать кучу поддержка кода, чтобы сделать работу с неправильным типом менее болезненной, и в значительной степени гарантировано, что в какой-то момент вам нужно будет указать область, которая больше или меньше обычной области. То же самое и с датами: вы можете использовать «полдень» в качестве обычного времени для указания дат, но затем вы попадаете в часовые пояса, потому что люди ожидают указывать даты по местному времени, а не по UTC. И даже если вы найдете приемлемый способ использования DateTime для указания даты, вам потребуется дополнительная информация, чтобы узнать, является ли она абсолютной или относительной датой: 4 июля, 1776 или каждый 4 июля? Что если вы хотите повторить, используя другой период? И у календарей есть все виды сумасшедших проблем: некоторые месяцы длиннее других, некоторые годы длиннее других, некоторые дни даже длиннее других, и в некоторых календарях есть пробелы. Вы не захотите решать эти проблемы только целыми днями, потому что одни и те же проблемы возникают в течение более коротких периодов времени: вы, вероятно, хотели бы иметь возможность писать код, который выражает «принимать по 1 таблетке каждые 4 часа» так же легко, как « группа собирается каждую третью пятницу ".
Итак, в работе с датами много сложностей. Относительно (без каламбура) легко обеспечить тип, который указывает момент времени, и работать с ним, как с числом, но чрезвычайно сложно предоставить тип, который обращается ко всем способам использования дат.
Как уже отмечалось, существуют являются языки и библиотеки , которые обеспечивают хорошую поддержку для дат, и это часто является хорошей идеей , чтобы использовать их с учетом его довольно трудно получить дату связанной код точно.
источник
Существует много таких типов в разных библиотеках для разных языков. Почти наверняка есть один для вашего текущего языка. У утилит Java был ужасный API для вычисления времени, но введение пакета java.time сделало жизнь намного лучше. См. Java.time.LocalDate, содержащий значение года-месяца-дня, или java.time.MonthDay, содержащий только номер месяца и дня.
источник
Календарная манипуляция - один из самых плохо понимаемых аспектов вычислительной техники. Целые книги были написаны на эту тему. @MichealBlackburn абсолютно прав, когда запрашивает тип данных только для даты, который не разрешается до определенной точки на временной шкале и подлежит повторной интерпретации. Исторически существовали законные споры о значении даты. Нужно смотреть не дальше, чем принять григорианский календарь, чтобы понять, насколько сложным он может стать. Кроме того, годы не всегда начинались 1 января, даже в Западной Европе и ее колониях ( например , Британия и Британская Америка начали год 25 марта).
источник
В ответ на:
Наиболее распространенной причиной может быть «потому что это не обязательно». Если вам нужна дата и время, не заботящиеся о часах, минутах, секундах и т. Д., Вы просто инициализируете ее следующим образом:
Если вы хотите, вы можете продлить DateTime самостоятельно:
Примечание: я намеренно игнорирую время и часовой пояс по умолчанию. Неважно, на что вы их устанавливаете, если они одинаковы для всех
Date
. Вы можете сделать случай для UTC. Вы можете обосновать использование часового пояса, в котором находится ваш сервер - в любом случае я не думаю, что это важно для представления неточных значений, таких какDate
. То же самое со временем по умолчанию - вы можете сделать это 0, вы можете сделать это в полдень. Это не важно Если Facebook присылает мне уведомление о дне рождения в 00:01, но я родился в 23:59, мне все равно, и я не буду обижаться, что у них больше 12 часов.Выше приведено в Java, но будет работать аналогично на любом языке с
DateTime
и наследование. У Java на самом деле есть множество способов решения этой проблемы, и вышесказанное устарело (они хотят, чтобы вы использовалиCalendar
сейчас). Но как и другие сообщения в комментариях, некоторые языки на самом деле сделать обеспечитьDate
класс, по- видимому именно по этой причине.По всей вероятности, каждая
Date
реализация, вероятно, является просто оберткой для языкаDateTime
и обнуляет время. В противном случае вам потребуется дублированный код для решения таких проблем, как количество дней между двумя датами / датами или два дня.Date
s (как насчет 29 февраля и 1 марта?). Такие вещи обычно решаются вDateTime
классе. Имеет смысл повторно использовать один и тот же код дляDate
.источник
LocalDate
, илиDate
типа класс , и вы должны роллом своих собственного ».new Date(2000, 1, 1);
иnew Date(2000, 1, 1);
? Можете ли вы сказать, какой из них имеет пустые часы, минуты и секунды? Если вы беспокоитесь о дополнительных функций , показывая вверх (как setMinutes ()), то вы могли бы пойти по пути иметьDate
оберткуDateTime
вместо унаследованного от него, а затем вы только разоблачить setYear, setMonth, setDay и т.д. И это, конечно , не менее правильно, чем DateTime библиотеки, которую вы используете.