Лучший способ сохранить время (чч: мм) в базе данных
Я хочу хранить время в таблице базы данных, но нужно хранить только часы и минуты. Я знаю, что могу просто использовать DATETIME и игнорировать другие компоненты даты, но как лучше всего это сделать, не сохраняя больше информации, чем мне действительно нужно?
15 ответов
Вы можете сохранить его как целое число числа минут после полуночи:
например.
0 = 00:00
60 = 01:00
252 = 04:12
Вам, однако, нужно написать некоторый код, чтобы воссоздать время, но это не должно быть хитрым.
Если вы используете SQL Server 2008+, рассмотрите TIME
тип данных. Статья SQLTeam с большим количеством примеров использования.
DATETIME начало DATETIME конец
Я умоляю вас использовать вместо этого два значения DATETIME, помеченные чем-то вроде event_start и event_end.
Время сложное дело
Большая часть мира в настоящее время приняла метрическую систему на основе мерзости для большинства измерений, правильно или неправильно. В целом это хорошо, потому что, по крайней мере, все мы можем согласиться с тем, что ag - это мл, это кубический сантиметр. По крайней мере, примерно так. Метрическая система имеет много недостатков, но, по крайней мере, она постоянно ошибочна на международном уровне.
Однако со временем мы имеем; 1000 миллисекунд в секунду, от 60 секунд до минуты, от 60 минут до часа, 12 часов для каждой половины дня, примерно 30 дней в месяц, которые варьируются в зависимости от месяца и даже рассматриваемого года, каждая страна имеет смещение времени по сравнению с другими время форматирования в разных странах различно.
Это много, чтобы переварить, но в таком сложном сценарии невозможно найти простое решение.
Некоторые углы можно обрезать, но есть такие, где не стоит
Хотя верхний ответ здесь предполагает, что вы сохраняете целое число минут после полуночи, может показаться вполне разумным, я научился избегать этого трудным путем.
Причины для реализации двух значений DATETIME для увеличения точности, разрешения и обратной связи.
Все это очень удобно, когда дизайн дает нежелательные результаты.
Я храню больше данных, чем требуется?
Изначально может показаться, что хранится больше информации, чем мне требуется, но есть веская причина принять этот удар.
Хранение этой дополнительной информации почти всегда приводит к экономии времени и усилий в долгосрочной перспективе, потому что я неизбежно обнаруживаю, что когда кому-то говорят, сколько времени заняло что-то, они также захотят узнать, когда и где произошло событие.
Это огромная планета
В прошлом я был виновен в том, что игнорировал, что есть другие страны на этой планете, кроме моей собственной. В то время это казалось хорошей идеей, но это ВСЕГДА приводило к проблемам, головным болям и потерянному времени в будущем. ВСЕГДА учитывайте все часовые пояса.
C#
DateTime прекрасно отображает строку в C#. Метод ToString(string Format) компактен и прост для чтения.
Например
new TimeSpan(EventStart.Ticks - EventEnd.Ticks).ToString("h'h 'm'm 's's'")
SQL-сервер
Кроме того, если вы читаете свою базу данных отдельно от интерфейса вашего приложения, тогда dateTimes легко читать с первого взгляда, и выполнять вычисления на них просто.
Например
SELECT DATEDIFF(MINUTE, event_start, event_end)
Стандарт даты ISO8601
Если вы используете SQLite, у вас этого нет, поэтому вместо этого используйте текстовое поле и сохраните его в формате ISO8601, например.
"2013-01-27T12: 30: 00 +0000"
Заметки:
Это использует 24 часовые часы *
Часть +0000 ISO8601 отображается непосредственно на широту в координате GPS. Поэтому стоит подумать, стоит ли хранить данные о долготе, широте и высоте над уровнем моря. Это будет зависеть от приложения.
ISO8601 - это международный формат.
Вики очень хороша для дальнейшей информации на http://en.wikipedia.org/wiki/ISO_8601.
Дата и время хранятся в международном времени, а смещение записывается в зависимости от того, где в мире было сохранено время.
По моему опыту, всегда необходимо хранить полную дату и время, независимо от того, думаю ли я, когда я начинаю проект. ISO8601 - это очень хороший, перспективный способ сделать это.
Дополнительные советы бесплатно
Также стоит объединить события в цепочку. Например, если вы записываете гонку, все событие может быть сгруппировано по racer, race_circuit, circuit_checkpoints и circuit_laps.
По моему опыту также целесообразно определить, кто сохранил запись. Либо в виде отдельной таблицы, заполненной триггером, либо в качестве дополнительного столбца в исходной таблице.
Чем больше вы положите, тем больше вы получите
Я полностью понимаю желание быть как можно более экономичным с пространством, но я бы редко делал это за счет потери информации.
Эмпирическое правило с базами данных, как говорится в заголовке, база данных может сказать вам только то, для чего она имеет данные, и может быть очень дорого обходить исторические данные, заполняя пробелы.
Решение состоит в том, чтобы сделать это правильно с первого раза. Это, конечно, легче сказать, чем сделать, но теперь вы должны глубже понять эффективный дизайн базы данных и впоследствии иметь гораздо больше шансов сделать это правильно с первого раза.
Чем лучше ваш первоначальный дизайн, тем дешевле будет ремонт.
Я только говорю все это, потому что, если бы я мог вернуться назад во времени, то это то, что я бы сказал себе, когда попаду туда.
Просто храните обычное время и игнорируйте все остальное. Зачем тратить дополнительное время на написание кода, который загружает int, манипулирует им и преобразует его в datetime, когда вы можете просто загрузить datetime?
Поскольку вы не упомянули об этом, если вы используете SQL Server 2008, вы можете использовать тип данных time, в противном случае используйте минуты с полуночи
Если вы используете MySQL, используйте тип поля TIME и соответствующую функциональность, которая поставляется вместе с TIME.
00:00:00 - стандартный формат времени Unix.
Если вам когда-либо придется оглядываться назад и просматривать таблицы вручную, целые числа могут быть более запутанными, чем фактическая отметка времени.
SQL Server на самом деле хранит время как доли дня. Например, 1 целый день = значение 1. 12 часов - это значение 0.5.
Если вы хотите сохранить значение времени без использования типа DATETIME, сохранение времени в десятичной форме будет соответствовать этой потребности, а также сделает преобразование в DATETIME простым.
Например:
SELECT CAST(0.5 AS DATETIME)
--1900-01-01 12:00:00.000
Хранение значения в формате DECIMAL(9,9) будет занимать 5 байт. Однако, если точность не имеет первостепенного значения, REAL будет использовать только 4 байта. В любом случае совокупный расчет (т. Е. Среднее время) можно легко рассчитать по числовым значениям, но не по типам данных / времени.
Вместо минут после полуночи мы храним его как 24-часовой формат, как SMALLINT.
09:12 = 912 14:15 = 1415
при преобразовании обратно в "удобочитаемую форму" мы просто вставляем двоеточие:"два символа справа. Левый блок с нулями, если вам нужно. Сохраняет математику в любом случае и использует несколько меньших байтов (по сравнению с varchar), плюс принудительно указывает, что значение является числовым (а не буквенно-цифровым)
Довольно глупо, хотя... в MS SQL уже много лет должен был быть тип данных TIME ИМХО...
Я бы преобразовал их в целое число (ЧЧ *3600 + ММ *60) и сохранил бы его таким образом. Небольшой объем памяти, и все же достаточно легко работать с.
Вы уверены, что вам понадобятся только часы и минуты? Если вы хотите сделать что-то значимое с этим (например, вычислить промежуток времени между двумя такими точками данных), не имея информации о часовых поясах и DST, это может дать неверные результаты. Часовые пояса, возможно, не применяются в вашем случае, но DST наверняка будет.
Я думаю, что вы просите переменную, которая будет хранить минуты как число. Это можно сделать с различными типами целочисленных переменных:
SELECT 9823754987598 AS MinutesInput
Затем в вашей программе вы можете просто просмотреть это в форме, которую вы хотите, вычислив:
long MinutesInAnHour = 60;
long MinutesInADay = MinutesInAnHour * 24;
long MinutesInAWeek = MinutesInADay * 7;
long MinutesCalc = long.Parse(rdr["MinutesInput"].toString()); //BigInt converts to long. rdr is an SqlDataReader.
long Weeks = MinutesCalc / MinutesInAWeek;
MinutesCalc -= Weeks * MinutesInAWeek;
long Days = MinutesCalc / MinutesInADay;
MinutesCalc -= Days * MinutesInADay;
long Hours = MinutesCalc / MinutesInAnHour;
MinutesCalc -= Hours * MinutesInAnHour;
long Minutes = MinutesCalc;
Возникает проблема, когда вы запрашиваете эффективность для использования. Но, если у вас мало времени, просто используйте обнуляемый BigInt для хранения вашего значения минут.
Значение null означает, что время еще не записано.
Теперь я объясню в форме поездки в космос.
К сожалению, столбец таблицы будет хранить только один тип. Поэтому вам нужно будет создать новую таблицу для каждого типа, как это требуется.
Например:
Если MinutesInput = 0.. 255, тогда используйте TinyInt (Преобразовать, как описано выше).
Если MinutesInput = 256.. 131071, тогда используйте SmallInt (примечание: минимальное значение SmallInt равно -32768. Поэтому при сохранении и извлечении значения используйте отрицание и добавьте 32768, чтобы использовать полный диапазон перед преобразованием, как описано выше).
Если MinutesInput = 131072.. 8589934591, используйте Int (примечание: отрицание и добавьте 2147483648 при необходимости).
Если MinutesInput = 8589934592.. 36893488147419103231, тогда используйте BigInt (Примечание: добавьте и при необходимости отмените 9223372036854775808).
Если MinutesInput> 36893488147419103231, тогда я лично использую VARCHAR(X), увеличивая X по мере необходимости, поскольку char является байтом. Я должен буду вернуться к этому ответу позже, чтобы полностью описать его (или, может быть, сотрудник stackruee может закончить этот ответ).
Поскольку каждому значению, несомненно, потребуется уникальный ключ, эффективность базы данных будет очевидна только в том случае, если диапазон хранимых значений представляет собой хорошее сочетание между очень маленьким (близким к 0 минутам) и очень высоким (больше 8589934591).
До тех пор, пока сохраняемые значения не достигнут значения, превышающего 36893488147419103231, у вас также может быть один столбец BigInt для представления ваших минут, поскольку вам не нужно тратить Int на уникальный идентификатор и другое Int для хранения значения минут.
Попробуйте smalldatetime. Это может не дать вам то, что вы хотите, но это поможет вам в ваших будущих потребностях в манипуляциях с датой / временем.
Экономия времени в формате UTC может помочь лучше, как предложила Кристен.
Убедитесь, что вы используете 24-часовые часы, потому что в UTC нет меридиана AM или PM.
Пример:
- 4:12 утра - 0412
- 10:12 утра - 1012
- 14:28 - 1428
- 23:56 - 2356
Все еще предпочтительнее использовать стандартный четырехзначный формат.
Хранить ticks
как long
/bigint
, которые в настоящее время измеряются в миллисекундах. Обновленное значение можно найти, посмотрев на TimeSpan.TicksPerSecond
значение.
Большинство баз данных имеют тип DateTime, который автоматически сохраняет время в виде галочек за кулисами, но в случае некоторых баз данных, например, SqlLite, хранение галочек может быть способом хранения даты.
Большинство языков позволяют легко конвертировать из Ticks
→ TimeSpan
→ Ticks
,
пример
В C# код будет:
long TimeAsTicks = TimeAsTimeSpan.Ticks;
TimeAsTimeSpan = TimeSpan.FromTicks(TimeAsTicks);
Имейте в виду, хотя, потому что в случае SqlLite, который предлагает только небольшое количество различных типов, которые; INT
, REAL
а также VARCHAR
Необходимо будет хранить количество тиков в виде строки или двух. INT
клетки объединены. Это потому что INT
32-битное число со знаком, тогда как BIGINT
это 64-битный номер со знаком.
Заметка
Однако я предпочитаю хранить дату и время как ISO8601
строка.
ИМХО, какое наилучшее решение в некоторой степени зависит от того, как вы храните время в остальной части базы данных (и остальной части вашего приложения)
Лично я работал с SQLite и стараюсь всегда использовать метки времени Unix для хранения абсолютного времени, поэтому при работе с временем суток (как вы и просили) я делаю то, что пишет Глен Солсберри в своем ответе, и сохраняю количество секунд с полуночи
Принимая этот общий подход, люди (включая меня!), Читающие код, будут менее смущены, если я использую один и тот же стандарт везде