2022.11.12

Timezone 날짜 계산

시간은 중요하다. 특히 글로벌한 서비스를 구성할 예정이라면 더욱 중요한 요소이다. 그 외에도 서비스 중 시간, 날짜 계산이 필요한 경우 Timezone에 대해서 생각하기 시작한다. 타임존을 설정하면 사용자의 지역에 따라 해당하는 시간을 보여주거나 연산이 가능하다.


Rails에서 Timezone 설정하기


rails에서 TimeZone을 설정하는 경우 생각해야하는 요소는 두 가지이다. time_zone, active_record의 타임존 설정인데, Rails 시간을 보여주는 설정과 액티브 레코드 설정으로 실제 데이터 베이스에 지정되는 타임존이다. 설정하지 않으면 default로 utc가 들어간다.


  • config.time_zone
  • config.active_record.default_timezone


각각 한국 시간대로 설정한다고 가정하고 작성하면 다음과 같다. 이 경우, 데이터 베이스에 저장되는 값은 local의 값, 실제로 rails에서 보여지는 값은 서울 시간대이다.


config.time_zone = ‘Seoul’

config.active_record.default_timezone = :local #utc


설정한 후 확인하기 위해 아래 명령어를 작성하면, 리스트에 우리가 설정한 seoul이 있는지 확인하자. 있다면 잘 설정된 것이다.


rails time:zones:all

다른 나라에 대한 시간은 아래 참고자료를 참고 하자.

  • 참고자료

[ Ruby on Rails ] 시간대 서울로 맞추기 ( Timezone Seoul )

ActiveSupport::TimeZone



시간 계산하기

설정이 끝났다면, 해당 시간에 따른 계산을 할 수 있다. 만약 config.time_zone을 하지 않았다면, ActiveSupport::TimeWithZone 인스턴스를 생성해야 한다. 하지만, 설정을 했다면, Time.zone을 통해 쉽게 연산할 수 있다.


어제, 오늘, 내일

어제 : Time.zone.yesterday

오늘 : Time.zone.now

내일 : Time.zone.tomorrow


지정한 시간 : Time.zone.parse(’2021-01-13 12:00:00’) # 시각, 날짜, 년도만 쓸 수도 있음.

포멧팅 : Time.zone.strptime('1999-12-31 14:00:00', '%Y-%m-%d %H:%M:%S')


지정한 시간, 포멧팅에 str 부분이 잘못되었다면 ArgumentError가 발생한다. 만약 해당 날짜에서 초, 분, 시간, 날짜, 주, 달, 년도 를 더하는 경우 advance를 이용하면 된다. 빼는 경우는 ago를 사용한다. 해당 내용 중 일부를 바꾸는 경우 change를 이용할 수 도 있다.



time = Time.zone.now

# advance 더하기
time.now.advance(days: 1) # 하루 더해진다.
time.now.advance(weeks: 2) # 2주 더해진다. 

# ago 빼기
time.now.ago(1.day) # 하루 뺀다.
time.now.ago(2.weeks) # 2주 뺀다.

# change 요소 바꾸기
time.change(hour: 11) # 시간이 11시가 된다.
time.change(zone: "utc") # 해당 객체의 타임존을 바꾼다.

10.days.ago # now가 default인 것 같다.



테스트에서 시간 조종하기


rails 테스트에서 특정 시간에 대해서 설정하고 싶은 경우, Rails time helper를 이용하거나 Timecop을 많이 이용한다. 개인적으로 TimeHelper보다는 Timecop이 더 간편하고 사용하기 쉽다.


Timecop과 Timehelper의 차이는 Timecop에는 scale 메소드가 있지만, Timehelper에는 해당 메소드가 없다는 것이다. scale은 아래의 Timecop 과 같이 원하는 값 만클 시간을 흐르게 조정할 수 있다.


helper를 이용하면 단순히 어느 시점의 시간으로 고정을 시키거나, travel을 통해서 다시 설정을 해야하는 등의 번거로움이 있기 때문에, 시간이 중요한 테스트에서 더 유연하게 조절하기 위해서는 Timecop 사용이 더 좋다고 할 수 있다. 또한, Timecop의 경우 safemode, 블록 단위에 설계가 가능하기 때문에 Timecop을 더 선호한다.


차이점

  Timehelper Timecop
freeze Timehelper.freeze Timecop.freeze
travel Timehelper.travel_to Timecop.travel
scale 없음 Timecop.scale



Timecop


시간을 사용해야할 때는 주로 테스트에서 일어난다. rspec에서 주로 Timecop을 이용한다. Timecop은 간단하다.


  • Timecop.freeze : 지정된 시간에 멈추기 (지정한 시간으로 고정)
  • Timecop.travel : 지정된 시간으로 설정 (설정 후 시간이 흐름)
  • Timecop.scale : 시간 흐르기 (원하는 값 만큼 시간이 흐름)


이렇게 시간을 조종하면, Timecop.return으로 초기화해주어야한다. 만약 블록 형식(safe_mode)로 작성된 경우 따로 지정하지 않아도 해당 블록 이후에 초기화 된다.

# not_safe mode
Timecop.freeze(...)
Timecop.return

# safe_mode
Timecop.freeze(...) do
...
end

만약 Timecop.safe_mode = true 으로 두면 무조건 블록 형식으로 작성하여야 동작한다.

https://github.com/travisjeffery/timecop

Categories:

Updated:

Leave a comment