2009-08-11 2 views
8

필자는 UTC를 사용하고있는 것으로 알고 있지만 시간대에 따라 약간의 시간차가있는 레일스 쿼리를 사용합니다. 간단히 말해서, 이러한 쿼리는 다른 대답을 줄 : 이 레일스 쿼리가 시간대에 따라 다르게 작동하는 이유는 무엇입니까?

>> Model.find(:all,:conditions=>['created_at<=?',(Time.now-1.hours).gmtime]).length 
=> 279 
>> Model.find(:all,:conditions=>['created_at<=?',(Time.now-1.hours)]).length 
=> 280 

DB를 실제로 지난 시간에 생성 한 모델을 포함하지 않습니다, 및 모델의 총 수는 280 그래서 첫 번째 쿼리가 올바른지입니다

.

그러나으로 environment.rb에서 내가 가진 :

config.time_zone = 'UTC' 

시스템 시간대 ('날짜'에 의해보고) (GMT + 1) BST는 - 그래서 어떻게 든이로 취급 받고 바람이 UTC 및 깨는 쿼리

이것은 다른 시간에 전달되는 쿼리를 매개 변수화해야 할 때 (내가 Time.parse()를 사용하여 변환 한) 모든 문제를 일으키고 있으며 UTC 시간으로 보내더라도 ' DST 문제가 많이 발생합니다. '.gmtime()'을 사용한다고해서 항상 문제가 해결되는 것은 아닙니다.

명백히 차이점은 암시 적 변환에 의해 어딘가에 발생하여 BST가 UTC로 잘못 처리되는 이유는 무엇입니까? 레일스가 타임 스탬프를 UTC로 저장하지 않습니까? Time 클래스 시간대를 인식하지 못합니까? 나는 레일즈 2.2.2를 사용하고있다.

그래서 여기서 무엇이 벌어지고 있는가? 그리고 그 주위를 프로그래밍하는 안전한 방법은 무엇인가?

편집, 몇 가지 추가 정보는 DB 및 시간 클래스가 무엇을하고 있는지 보여 :

>> Model.find(:last).created_at 
=> Tue, 11 Aug 2009 20:31:07 UTC +00:00 
>> Time.now 
=> Tue Aug 11 22:00:18 +0100 2009 
>> Time.now.gmtime 
=> Tue Aug 11 21:00:22 UTC 2009 

답변

13

Time 클래스는 직접 구성 시간대를 인식하지 못합니다. Rails 2.1은 많은 시간대 지원을 추가했지만, Time은 여전히 ​​현지 시간대를 사용합니다. 이것이 Time.now가 BST 시간을 반환하는 이유입니다.

Time.zone과 상호 작용하는 것이 좋습니다. Time 클래스 자체와 마찬가지로이 메서드를 호출 할 수 있지만 지정된 시간대에 반환합니다.

Time.zone.now # => Tue, 11 Aug 2009 21:31:45 UTC +00:00 
Time.zone.parse("2:30 PM Aug 23, 2009") # => Sun, 23 Aug 2009 14:30:00 UTC +00:00 

당신이 레일 때문에 (사용자가 지정한 다른 시간대를 경우에도) UTC 시간을 사용하는 당신은 시간을 비교하는 곳에 당신이 이제까지 데이터베이스에 쿼리를 할 경우와는 조심하지만, 반드시해야 할 또 다른 것은 항상 UTC를 데이터베이스에 저장합니다. 또한

Item.all(:conditions => ["published_at <= ?", Time.now.utc]) 

, 대신 Time.now-1.hour1.hour.ago을한다. 읽기가 쉽고 Rails는 자동으로 구성된 시간대를 사용합니다.

+0

재미있는 BST ...이 Time.utc Time.gmtime 동의어입니다 처리 할 것인가? 또한 >> Time.zone을 얻습니다. > # > 문제는 저의 사고 방식에 "8 월 11 일 22시 22 분 : 18 +0100 2009"과 "8 월 11 일 21:00 21:00:22 UTC 2009"같은 논리 시간을 의미합니다. 레일/루비는 SQL을 구축 할 때 단순히 오프셋을 무시하고있는 것 같습니다. – frankodwyer

+1

나는 Time # utc이 Time # gmtime의 별명 일 뿐이라고 생각한다.또한 정상 시간 (Time.now)을 다룰 때는 시간대 오프셋이 무시되지만 Time.zone.now를 사용할 때는 고려해야합니다. Time.zone을 항상 사용하려면 "utc"를 호출 할 필요가 없습니다. – ryanb

+0

덕분에 많은 도움이되었습니다. 그런 식으로 작동한다는 것은 나에게 비현실적이지만, 적어도 지금 어떤 일이 일어나는지 이해합니다. 그에 따라 코드를 변경했으며 문제를 해결 한 것으로 보입니다. 내 코드를 던지고있는 또 다른 한가지는 1.years가 1.weeks로 균등하게 나눌 수 없다는 것입니다. 나는 루프를하고 있었기 때문에 관련이 없지만 비슷한 오류가 발생했습니다. – frankodwyer

0

사용자가 설정해야하는 시간대는 영국이이 자동으로

Time.zone = 'UK' 
Time.zone.now 
=> Sun, 17 Oct 2010 02:09:54 BST +01:00 
+0

나는 이것이 지금 있어야한다고 생각한다. Time.zone = "London" – simonmorley

+0

예. 이제 런던이 될 것이다. – MatthewFord

0
start_date_format = DateTime.strptime(@start_date, date_format) 
start_date_format_with_hour = 
DateTime.strptime((start_date_format.to_i + timezone_offset*60*60).to_s,'%s').strftime(date_format) 

end_date_format = DateTime.strptime(@end_date, date_format) 
end_date_format_with_hour = DateTime.strptime((end_date_format.to_i + timezone_offset*60*60).to_s,'%s').strftime(date_format) 

@filters_date = "invoices.created_at >= ? AND invoices.created_at < ?", start_date_format_with_hour, end_date_format_with_hour 
+0

코드 일부만 삭제하면 거의 도움이되지 않는다. 코드가하는 일을 조금 설명해주십시오. – lexicore

관련 문제