데이터베이스에 시간 (hh : mm)을 저장하는 가장 좋은 방법


100

시간을 데이터베이스 테이블에 저장하고 싶지만 시간과 분만 저장하면됩니다. DATETIME을 사용하고 날짜의 다른 구성 요소를 무시할 수 있다는 것을 알고 있지만 실제로 필요한 것보다 더 많은 정보를 저장하지 않고이를 수행하는 가장 좋은 방법은 무엇입니까?


SQL Server 2005의 TIME에 해당하는 것은 무엇입니까?
Erran Morad 2014

@BoratSagdiyev SQL Server 2005에는 하나가 없기 때문에 제가 질문을했습니다.
Matthew Dresser 2014

답변:


135

자정을 지난 분의 정수로 저장할 수 있습니다.

예.

0 = 00:00 
60 = 01:00
252 = 04:12

그러나 시간을 재구성하려면 몇 가지 코드를 작성해야하지만 까다로워서는 안됩니다.


8
그런 다음 DATEADD ()를 사용하여 실시간으로 돌아갑니다. smallint도 충분합니다.
Joel Coehoorn

36
거기에 있었다 ... mins = dd % 60 및 hours = dd / 60 on int가 트릭을 수행합니다.
Osama Al-Maadeed

2
그것은 위대하고 단순하며 진지한 아이디어입니다. +1
whiskeysierra

7
작은 단점은 데이터베이스에 가독성의 부족이다
Jowen

일, 시간, 분의 변형을 저장해야합니다. SQL Server의 시간 데이터 유형은 23:59:59까지만 올라가므로 사용할 수 없습니다. 귀하의 답변에 영감을 받아 며칠 동안 세 개의 int 열을 사용하기로 결정했습니다. 최대 유연성을 위해 시간 : 분. 감사!
matao


15

DATETIME 시작 DATETIME 종료

대신 event_startevent_end 와 같은 레이블이 붙은 두 개의 DATETIME 값 을 사용 하시기 바랍니다 .

시간은 복잡한 사업

이제 세계 대부분이 대부분의 측정에 대해 옳든 그르 든 데 너리 기반 미터법을 채택했습니다. 이것은 전반적으로 좋습니다. 왜냐하면 적어도 우리 모두는 ag가 ml이고, 입방 cm라는 것에 동의 할 수 있기 때문입니다. 적어도 대략 그렇게. 미터법에는 많은 결함이 있지만 적어도 국제적으로는 지속적으로 결함이 있습니다.

그러나 시간이 지남에 따라 우리는 있습니다. 1 초에 1000 밀리 초, 60 초에서 1 분, 60 분에서 1 시간, 반나절마다 12 시간, 월별 약 30 일, 해당 월 및 연도에 따라 다르며, 각 국가는 다른 국가와 시간 오프셋이 있습니다. , 시간 형식은 국가마다 다릅니다.

소화해야 할 것은 많지만 길고 짧은 것은 그러한 복잡한 시나리오가 간단한 해결책을 갖는 것이 불가능합니다.

일부 모서리는 잘릴 수 있지만 더 현명한 부분이 있습니다.

여기에 대한 최고의 답변은 자정 이후에 몇 분의 정수를 저장하는 것이 완벽하게 합리적으로 보일 수 있음을 시사하지만 어려운 방법으로 그렇게하는 것을 피하는 법을 배웠습니다.

두 개의 DATETIME 값을 구현하는 이유는 정확도, 해상도 및 피드백의 증가 때문입니다.

이는 디자인이 원하지 않는 결과를 생성 할 때 매우 유용합니다.

필요한 것보다 더 많은 데이터를 저장하고 있습니까?

처음에는 내가 필요로하는 것보다 더 많은 정보가 저장되고있는 것처럼 보일 수 있지만이 히트를 가져야 할 좋은 이유가 있습니다.

이 추가 정보를 저장하면 거의 항상 장기적으로 시간과 노력을 절약 할 수 있습니다. 왜냐하면 누군가 무언가가 얼마나 오래 걸 렸는지 들었을 때 이벤트가 언제 어디서 일어 났는지 알고 싶어하기 때문입니다.

거대한 행성입니다

과거에 나는이 행성에 내 나라 외에 다른 나라가 있다는 것을 무시한 죄를지었습니다. 당시에는 좋은 생각처럼 보였지만 이로 인해 항상 문제, 두통 및 시간 낭비가 발생했습니다. 항상 모든 시간대를 고려하십시오.

씨#

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 시간제를 사용합니다 *

  • ISO8601의 시간 오프셋 (또는 +0000) 부분은 GPS 좌표의 경도 값에 직접 매핑됩니다 (일광 절약 또는 전국을 고려하지 않음).

TimeOffset=(±Longitude.24)/360 

... 여기서 ±는 동쪽 또는 서쪽 방향을 나타냅니다.

따라서 데이터와 함께 경도, 위도 및 고도를 저장할 가치가 있는지 고려할 가치가 있습니다. 이것은 응용 프로그램에 따라 다릅니다.

  • ISO8601은 국제 형식입니다.

  • 위키는 http://en.wikipedia.org/wiki/ISO_8601 에서 더 자세한 정보를 얻을 수 있습니다.

  • 날짜와 시간은 국제 시간으로 저장되며 오프셋은 시간이 저장된 위치에 따라 기록됩니다.

내 경험상 프로젝트를 시작할 때가 있다고 생각하는지 여부에 관계없이 항상 전체 날짜와 시간을 저장할 필요가 있습니다. ISO8601은 매우 훌륭하고 미래를 보장하는 방법입니다.

무료 추가 조언

체인처럼 이벤트를 함께 그룹화하는 것도 가치가 있습니다. 예를 들어 레이스를 기록하는 경우 전체 이벤트를 racer, race_circuit, circuit_checkpoints 및 circuit_laps별로 그룹화 할 수 있습니다.

제 경험상 누가 기록을 저장했는지 확인하는 것도 현명합니다. 트리거를 통해 채워진 별도의 테이블 또는 원래 테이블 내의 추가 열로.

더 많이 넣을수록 더 많이 나옵니다.

나는 가능한 한 공간적으로 경제적이 되려는 욕구를 완전히 이해하지만 정보를 잃어 버리는 대가로 그렇게하는 경우는 거의 없습니다.

데이터베이스의 경험 법칙은 제목에서 알 수 있듯이 데이터베이스는 데이터가있는만큼만 알려줄 수 있으며, 공백을 메우고 과거 데이터를 살펴 보는 데에는 비용이 많이들 수 있습니다.

해결책은 처음에 올바르게하는 것입니다. 이것은 말처럼 쉬운 일이지만 이제는 효과적인 데이터베이스 디자인에 대한 더 깊은 통찰력을 가지고 있어야하며, 이후에 처음부터 올바르게 만들 가능성이 훨씬 더 높아야합니다.

초기 설계가 좋을수록 나중에 수리 비용이 적게 듭니다.

내가 시간을 거슬러 올라갈 수 있다면 내가 거기에 도착했을 때 나 자신에게 말할 것이기 때문입니다.


2
"ISO8601의 +0000 부분은 GPS 좌표에서 위도에 직접 매핑됩니다"라는 의견이 잘못되었습니다. UTC로부터
Gary Walker

10

일반 날짜 시간을 저장하고 나머지는 모두 무시하십시오. 날짜 시간을로드 할 수있을 때 int를로드하고, 조작하고, 날짜 시간으로 변환하는 코드를 작성하는 데 추가 시간을 소비하는 이유는 무엇입니까?


3
한 가지 가능한 이유는 하드 드라이브의 공간을 절약하기 때문일 수 있습니다. DATETIME데이터 유형은 저장하는 데 4 바이트가 SMALLINT걸리지 만 예를 들어 데이터 유형은 1/4 만 차지합니다. 수천 개의 행만있는 경우 큰 차이는 없지만 많은 회사에서 행하는 수백만 개의 행이있는 경우 공간 절약은 상당 할 것입니다.
Sheridan

32
가능하지만, 12 명이이 질문에 답했으며, 각각에 대해 생각하는 데 15 분 정도 걸립니다. 그들이 모두 프로그래머이고 시간당 $ 50를 벌고 있다고 가정합니다. 이 문제에 대해 생각 하는 데 소요되는 시간을 감안하면 추가 바이트를 저장하기 위해 반짝이는 새 2TB 하드 드라이브를 구입할 수 있습니다.
Seth

우리가 여분의 바이트에 대해서만 이야기한다면 @Seth 당신이 맞습니다. 그러나 귀하의 제안은 1-2 명의 개발자가 참여하는 소규모 프로젝트 인 경우에만 가능합니다. 그러나 많은 개발자 (QA 포함)가있는 큰 프로젝트가 될 것입니다. 새로운 프로그래머가 이것을 알아 내려고 할 때 큰 문제가 될 것입니다. 아아, 우리 모두는 비즈니스 로직에 의존합니다.
중재자

클라우드 서비스를 사용하면 읽기 / 처리 된 바이트 당 비용을 지불하는 경우 디스크 공간 절약이 중요 할 수 있습니다.
RedShift

2
또 다른 재미있는 문제는 시간 구성 요소에 의존하는 경우 일년 중 다른 시간에 사용할 때 일광 절약 시간 조정을 고려하지 않는다는 것입니다.
크리스 Seufert

4

SQL Server 2008을 사용하는 경우 약간 언급하지 않았으므로 시간 데이터 유형을 사용할 수 있으며 그렇지 않으면 자정 이후 분을 사용할 수 있습니다.


3

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 바이트 만 소비합니다. 두 경우 모두 집계 계산 (즉, 평균 시간)은 숫자 값에서 쉽게 계산할 수 있지만 데이터 / 시간 유형에서는 계산할 수 없습니다.


"SQL Server는 실제로 시간을 하루의 일부로 저장합니다." 1900 년 1 월 1 일 (또는 그 이전) 이후의 날짜를 처음 4 바이트에 저장하고 시간 (밀리 초)을 두 번째 4 바이트에 저장한다고 생각합니다. (SmallDateTime은 날짜 범위가 더 좁은 각각에 대해 2 바이트를 사용하고 시간에 대해 밀리 초가 아닌 분을 사용합니다.)
Kristen

저는 (99.99 % 확실) 하루 중 시간이 분수라는 것을 알고 있습니다.
graham.reeds 2010-06-15

2

정수 (HH * 3600 + MM * 60)로 변환하여 저장합니다. 작은 저장소 크기로 작업하기에 충분히 쉽습니다.


2

MySQL을 사용하는 경우 TIME 필드 유형과 TIME과 함께 제공되는 관련 기능을 사용하십시오.

00:00:00은 표준 유닉스 시간 형식입니다.

손으로 테이블을 되돌아보고 검토해야하는 경우 정수는 실제 타임 스탬프보다 더 혼란 스러울 수 있습니다.


1

smalldatetime을 시도하십시오. 원하는 것을 제공하지 않을 수도 있지만 날짜 / 시간 조작에서 향후 요구 사항에 도움이 될 것입니다.


@mdresser가 <MSSQL 2005를 사용하는 경우 서버는 "out-of-range smalldatetime value"를 기준으로합니다
Fergus

1

시간과 분만 필요하다고 확신하십니까? 의미있는 작업을 수행하려는 경우 (예 : 두 데이터 포인트 사이의 계산 시간 범위) 시간대 및 DST에 대한 정보가 없으면 잘못된 결과를 얻을 수 있습니다. 시간대는 귀하의 경우에 적용되지 않을 수 있지만 DST는 가장 확실합니다.


1

자정을지나 몇 분이 아니라 24 시간 시계로 SMALLINT로 저장합니다.

09:12 = 912 14:15 = 1415

"사람이 읽을 수있는 형식"으로 다시 변환 할 때 오른쪽에서 두 문자 만 콜론 ":"을 삽입합니다. 필요한 경우 0이있는 왼쪽 패드. 각 방식으로 수학을 저장하고 몇 바이트 (varchar에 비해)를 사용하고 값을 영숫자가 아닌 숫자로 지정합니다.

그래도 꽤 구피 ... MS SQL에는 이미 IMHO에서 수년 동안 TIME 데이터 유형이 있어야했습니다 ...


Kristen은 절대적으로 정확하지만 단일 24 시간 기간을 나타내는 시간과 분에 대한 가정이 옳은 경우에만 가능합니다. 0..1439 분을 저장하려면 10 비트가 필요합니다. 즉, 원하는대로 사용할 수있는 추가 6 비트가 있으므로 창의력을 발휘할 여지가 있습니다. 5 비트를 사용하여 현재있는 시간대의 시간 오프셋을 저장하는 것이 좋습니다.하지만 질문자가 최대 시간 인 23:59 (1 분에서 자정까지) 만 저장하려는 경우에만
WonderWorker

1

당신이 요구하는 것은 분을 숫자로 저장할 변수입니다. 이는 다양한 유형의 정수 변수로 수행 할 수 있습니다.

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;

효율성 사용을 요청하는 문제가 발생합니다. 그러나 시간이 부족한 경우 nullable BigInt를 사용하여 분 값을 저장하십시오.

null 값은 시간이 아직 기록되지 않았 음을 의미합니다.

이제는 우주로의 왕복의 형태로 설명하겠습니다.

불행히도 테이블 열은 단일 유형 만 저장합니다. 따라서 필요에 따라 각 유형에 대해 새 테이블을 만들어야합니다.

예를 들면 :

  • MinutesInput = 0 .. 255 이면 TinyInt (위에서 설명한대로 변환)를 사용합니다.

  • MinutesInput = 256 .. 131071 이면 SmallInt 를 사용 합니다 (참고 : SmallInt의 최소값은 -32,768입니다. 따라서 위와 같이 변환하기 전에 전체 범위를 활용하기 위해 값을 저장 및 검색 할 때 32768을 부정하고 추가합니다).

  • MinutesInput = 131072 .. 8589934591 이면 Int 를 사용합니다 (참고 : 부정하고 필요에 따라 2147483648 추가).

  • MinutesInput = 8589934592 .. 36893488147419103231 이면 BigInt 를 사용합니다 (참고 : 필요에 따라 9223372036854775808 추가 및 부정).

  • MinutesInput> 36893488147419103231 이면 문자가 바이트이므로 필요에 따라 X를 증가시키는 VARCHAR (X)를 개인적으로 사용합니다. 나는 이것을 완전히 설명하기 위해 나중에이 대답을 다시 방문해야 할 것입니다 (또는 동료 스택 오버플로 이이 대답을 마칠 수 있습니다).

각 값에는 의심 할 여지없이 고유 한 키가 필요하므로 데이터베이스의 효율성은 저장된 값의 범위가 매우 작음 (0 분에 가깝게)과 매우 높음 (8589934591보다 큼) 사이의 적절한 혼합 인 경우에만 명백합니다.

저장되는 값이 실제로 36893488147419103231보다 큰 숫자에 도달 할 때까지 분 값을 저장하기 위해 고유 식별자 및 다른 int에 Int를 낭비 할 필요가 없기 때문에 분을 나타내는 단일 BigInt 열이있을 수 있습니다.


0

UTC 형식으로 시간을 절약하면 Kristen이 제안한 것처럼 더 나은 결과를 얻을 수 있습니다.

UTC에는 자오선 AM 또는 PM이 사용되지 않으므로 24 시간 시계를 사용하고 있는지 확인하십시오.

예:

  • 오전 4:12-0412
  • 오전 10:12-1012
  • 오후 2:28-1428
  • 오후 11:56-2356

표준 4 자리 형식을 사용하는 것이 여전히 선호됩니다.


0

현재 밀리 초 단위로 측정되는 / ticks로 저장합니다 . 업데이트 된 값은 값을보고 찾을 수 있습니다 .longbigintTimeSpan.TicksPerSecond

대부분의 데이터베이스에는 시간을 자동으로 틱으로 저장하는 DateTime 유형이 있지만 SqlLite와 같은 일부 데이터베이스의 경우 틱을 저장하는 것이 날짜를 저장하는 방법이 될 수 있습니다.

대부분의 언어는 TicksTimeSpan→ 에서 쉽게 변환 할 수 Ticks있습니다.

C #에서 코드는 다음과 같습니다.

long TimeAsTicks = TimeAsTimeSpan.Ticks;

TimeAsTimeSpan = TimeSpan.FromTicks(TimeAsTicks);

그러나 SqlLite의 경우에는 소수의 다른 유형 만 제공하기 때문에주의하십시오. INT, REAL그리고 VARCHAR틱 수를 문자열 또는 INT결합 된 두 개의 셀로 저장해야합니다 . INT이는는 32 비트 부호있는 숫자 BIGINT이고은 64 비트 부호있는 숫자 이기 때문 입니다.

노트

그러나 개인적으로 선호하는 것은 날짜와 시간을 ISO8601문자열 로 저장하는 것 입니다.


-1

IMHO 최고의 솔루션은 나머지 데이터베이스 (및 나머지 애플리케이션)에 시간을 저장하는 방법에 따라 어느 정도 다릅니다.

개인적으로 저는 SQLite와 함께 일했고 항상 절대 시간을 저장하기 유닉스 타임 스탬프 를 . 그래서 하루 중 시간을 다룰 때 (당신이 요청한 것처럼) 글렌 솔스 베리가 그의 대답에 쓴대로하고 자정 이후의 초 수를 저장합니다.

이 일반적인 접근 방식을 취할 때 사람들이 (나를 포함하여!) 어디서나 동일한 표준을 사용하면 코드를 읽는 것이 덜 혼란 스럽습니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.