IT와 관련된 공부를 진행하다 보면 타임 스탬프
라는 단어를 접할 수 있다.
그대로 직역하면 시간 도장 이라는 의미인데 말 그대로 특정한 시점에 도장을 찍는다고 보면 될 것 같다.
IT 에서는 일이 발생해서 컴퓨터에 기록된 시간을 의미하는데, 주로 어떤 일이 발생한 시간을 비교하거나 두 작업 사이에 어느정도의 시간이 경과되었는지를 알아내기 위해 사용한다.
타임스탬프
를 알기 위해서는 GMT
와 UTC
라는 용어를 알 필요가 있다.
GMT
란 그리니치 천문대에서 측정한 평균태양시를 의미한다.
과거에 태양의 움직임 즉 지구의 자전과 공전을 기준으로 시간을 결정한 것이다.
지구의 운동에서 하루의 평균 길이를 결정하고 여기서 1/24를 1시간으로, 1시간의 1/60을 1분으로, 1분의 1/60을 1초라고 정의한 것이다.
그런데, 과학이 발전하면서 골치아픈 문제가 발생했다.
지구의 자전속도가 일치하지 않는다는 것을 발견한 것이다.
이로인해 지구의 움직임 외에 다른 무언가를 기준으로 시간을 측정할 필요가 생겼다.
지구의 움직임을 통해 시간을 측정하는 방식에 문제가 생기자 대안으로 나타난 것이 원자의 움직임을 통해 시간을 측정하는 방식이다.
원자는 바닥상태와 들뜬 상태를 반복하며 에너지를 방출할 때 그 주기가 일정한데, 이 특성을 이용하여 시간을 측정하는 기준으로 활용한 것이다.
이렇게 태양의 움직임 대신에 원자 시계를 기준으로 세운 시간 체계를 원자시
라고 하며, 전세계에 400여개의 원자시계를 설치하여 시간의 오차를 보정하고 있는데, 이렇게 세계 각지에 흩어진 원자 시계를 통해 보정되는 시간 체계를 국제원자시
라고 한다.
원자를 기준으로 시간을 측정하면 1초보다 훨씬 적은 단위로 측정이 가능하다.
하지만, 일상 생활에서는 1초 미만의 단위를 다루는 것은 쉽지 않기 때문에 국제 원자시를 바탕으로 1초단위의 시간까지만 맞춰 놓은 것을 UTC
라고 한다.
Java
의 패키지에는 Timestamp
라는 클래스가 존재한다.
위의 그림은 Timestamp
클래스의 일부이다.
java.util.Date
를 상속해 만든것을 알 수 있고, @Deprecated
어노테이션이 붙어있는 생성자를 보면 과거에는 int
타입의 년도, 월, 일, 시간, 분 등의 파라미터를 입력해서 인스턴스를 생성했지만 이제 곧 해당 생성자를 지원하지 않는다는 것을 알 수 있다.
@Deprecated
어노테이션이 붙어있는 생성자 아래에는 long
타입 변수를 파라미터로 받는 생성자를 확인할 수 있다.
해당 생성자는 super
메소드를 이용해 Date
클래스에 있는 fastTime
이라는 변수값을 수정한다.
이 때 생성자에 전달하는 파라미터는 위의 시간값이라는 것을 알 수 있다.
아래에는 친절하게 System.currentTimeMills
메소드를 예시로 들어주까지 했다.
이제 실제로 해당 클래스를 사용해 타임스탬프
값을 확인해보자.
Timestamp
의 생성자에 들어갈 변수 값은 위에서 제시한 System.currentTimeMills
메소드를 통해 구해준다.
해당 메소드는 현재 시간과 1970년 1월 1일 자정
과의 차이를 밀리세컨드(1/1000초) 값으로 반환한다.
import java.sql.Timestamp;
public class TimestampSample {
public static void main(String[] args) {
Long datetime = System.currentTimeMillis();
Timestamp timestamp = new Timestamp(datetime);
System.out.println("Datetime = " + datetime);
System.out.println("Timestamp: "+timestamp);
}
}
System.currentTimeMills
메소드를 통해 구한 시간 값과 Timestamp
클래스를 통해 구한 시간값을 출력해보겠다.
두 값이 서로 다르다는 것을 알 수 있다.
먼저 Datetime
은 현재 시간과 1970년 1월 1일 자정
과의 차이를 밀리세컨드(1/1000초) 값으로 반환한 것이다.
다음으로 Timestamp
의 값은 위의 시간을 이용해 우리가 아는 시간의 포맷으로 변경한 것이다.
그렇다면 해당 Timestamp
값을 구하는 과정을 살펴보자.
import java.sql.Timestamp;
public class TimestampSample {
public static void main(String[] args) {
Long datetime = System.currentTimeMillis();
Timestamp timestamp = new Timestamp(datetime);
System.out.println("Datetime = " + datetime);
System.out.println("Timestamp: "+timestamp);
}
}
다시 예제 코드를 보면 Timestamp
값을 출력하는 부분이 객체명을 통해 그대로 출력되는 것을 볼 수 있다.
이를 통해 Timestamp
클래스에는 toString
메소드가 오버라이딩 되어 있다는 것을 알 수 있다.
해당 메소드의 일부분이다.
super
를 통해 상속받은 클래스로부터 년도, 월, 시간 등을 받아오는 것을 볼 수 있다.
대표적으로 year
값을 받아오는 부분을 보면 Date
클래스의 getYear
메소드에서 1900을 빼주고 Timestamp
클래스의 toString
메소드에서 1900을 더해주므로 year
값을 구하고 있다.
나머지 month
, day
, hour
등의 변수들도 Date
클래스에 있는 밀리세컨드로 표현한 현재 시간값에 일정한 보정을 하여 년, 월, 일, 시간 등의 값을 가져오는 것을 알 수 있다.
위의 Date
클래스의 생성자를 보면 파라미터로 1970년 1월 1일의 자정
을 기준으로 하는 값을 받는 것을 알 수 있다.
그런데 1970년 1월 1일의 자정
에는 무슨 의미가 있을까?
결론부터 말하면 UTC
시간을 기준으로 1970년 1월 1일 자정
은 UNIX 시간
의 기준이 되는 시간이다.
UNIX 시간
이란 유닉스 계열의 운영체제를 사용하는 컴퓨터에서 시간을 표시하는데 사용되는 방식인데 1970년 1월 1일 자정
부터 현재까지 얼마나 시간이 흘렀는지를 정수로 나타낸다.
말 그대로 UNIX
에서 기준이 되는 시간이기 때문에 알게모르게 꽤나 자주 보는 시간이기도 하다.
2038년 문제
는 UNIX 시간
에 32bit
정수형을 사용하는 서버들에서 나타나게 될 크리티컬한 문제이다.
32bit
의 정수형은 양수로 0~2^31-1
범위의 값을 나타낼 수 있다.
그런데 2^31-1
에서 1초가 더 지나면 바이너리 값이 01111111 11111111 11111111 11111111
에서 10000000 00000000 00000000 00000000
으로 변경되면서 음수값이 된다.