2011-02-28 4 views
4

Joda가 버그 일 수 있다고 생각하며 문제가 있습니다. 그러나 내가 도서관을 사용하면서 실수를 저지르고있을 가능성이 있으므로 제게 의견을주십시오.DST 시간대가 아닌 Joda 시간 변환이 잘못되었습니다.

우리는 데이터베이스 저장 형식 (UTC)과 사용자 시간대 환경 설정간에 시간을 변환하기 위해 생산 단계에서 joda를 사용 해왔다. 이 시스템을 사용하는 직원은 일광 절약 시간을 준수하지 않는 애리조나 출신입니다. 무엇보다도이 시스템은 전국 스포츠 경기의 시작 시간을 추적합니다.

우리는 시간 변경 전날 우리가 잘못된 결과를 얻고 있다는 것을 알게 될 때까지 Joda는 우리에게 큰 도움이되었습니다. 우리는 joda가 특정 시간대의 적절한 시간이 아닌 UTC 자정의 일광 절약 시간으로 변경되는 것으로 나타났습니다. 또한이 문제는 DST 관측 상태에서 애리조나와 같은 비 DST 상태로 시간을 변환 할 때만 발생합니다.

이 문제를 설명하는 전체 테스트 사례를 작성했습니다. 보시다시피, joda는 모든 미국/동부 -> 미국/태평양 테스트 케이스에 대해 예상 된 결과를 제공합니다. US/Arizona -> US/Pacific의 경우, 11 월이 변경되기 전과 그 이후에 일년 내내 작동합니다. 그러나 시간 변경 당일 (6 일째)에는 시간이 잘못되었습니다. 행진 시간 변경과 관련하여 문제가있을 수 있습니다. 아직 완전히 철저히 테스트하지는 않았습니다.

=== November 1st, Expected Result (0 hour) === 
java: 
Converting 2010-11-01 09:00 from US/Arizona to US/Pacific. 
Result: 2010-11-01 09:00. Change (0 hour). 

joda: 
Converting 2010-11-01 09:00 from US/Arizona to US/Pacific. 
Result: 2010-11-01 09:00. Change (0 hour). 

======================================= 

=== November 6th, Expected Result (0 hour) === 
java: 
Converting 2010-11-06 09:00 from US/Arizona to US/Pacific. 
Result: 2010-11-06 09:00. Change (0 hour). 

joda: 
Converting 2010-11-06 09:00 from US/Arizona to US/Pacific. 
Result: 2010-11-06 08:00. Change (-1 hour). 

======================================= 

=== November 12th, Expected Result (-1 hour) === 
java: 
Converting 2010-11-12 09:00 from US/Arizona to US/Pacific. 
Result: 2010-11-12 08:00. Change (-1 hour). 

joda: 
Converting 2010-11-12 09:00 from US/Arizona to US/Pacific. 
Result: 2010-11-12 08:00. Change (-1 hour). 

======================================= 

=== March 12th, Expected Result (-1 hour) === 
java: 
Converting 2010-03-12 09:00 from US/Arizona to US/Pacific. 
Result: 2010-03-12 08:00. Change (-1 hour). 

joda: 
Converting 2010-03-12 09:00 from US/Arizona to US/Pacific. 
Result: 2010-03-12 08:00. Change (-1 hour). 

======================================= 

=== March 14th, Expected Result (0 hour) === 
java: 
Converting 2010-03-14 09:00 from US/Arizona to US/Pacific. 
Result: 2010-03-14 09:00. Change (0 hour). 

joda: 
Converting 2010-03-14 09:00 from US/Arizona to US/Pacific. 
Result: 2010-03-14 09:00. Change (0 hour). 

======================================= 

=== November 1st, Expected Result (-3 hour) === 
java: 
Converting 2010-11-01 09:00 from US/Eastern to US/Pacific. 
Result: 2010-11-01 06:00. Change (-3 hour). 

joda: 
Converting 2010-11-01 09:00 from US/Eastern to US/Pacific. 
Result: 2010-11-01 06:00. Change (-3 hour). 

======================================= 

=== November 6th, Expected Result (-3 hour) === 
java: 
Converting 2010-11-06 09:00 from US/Eastern to US/Pacific. 
Result: 2010-11-06 06:00. Change (-3 hour). 

joda: 
Converting 2010-11-06 09:00 from US/Eastern to US/Pacific. 
Result: 2010-11-06 06:00. Change (-3 hour). 

======================================= 

=== November 12th, Expected Result (-3 hour) === 
java: 
Converting 2010-11-12 09:00 from US/Eastern to US/Pacific. 
Result: 2010-11-12 06:00. Change (-3 hour). 

joda: 
Converting 2010-11-12 09:00 from US/Eastern to US/Pacific. 
Result: 2010-11-12 06:00. Change (-3 hour). 

======================================= 

=== March 12th, Expected Result (-3 hour) === 
java: 
Converting 2010-03-12 09:00 from US/Eastern to US/Pacific. 
Result: 2010-03-12 06:00. Change (-3 hour). 

joda: 
Converting 2010-03-12 09:00 from US/Eastern to US/Pacific. 
Result: 2010-03-12 06:00. Change (-3 hour). 

======================================= 

=== March 14th, Expected Result (-3 hour) === 
java: 
Converting 2010-03-14 09:00 from US/Eastern to US/Pacific. 
Result: 2010-03-14 06:00. Change (-3 hour). 

joda: 
Converting 2010-03-14 09:00 from US/Eastern to US/Pacific. 
Result: 2010-03-14 06:00. Change (-3 hour). 

======================================= 

그리고 여기에 전체 테스트 케이스이다 :

package com.test.time; 

import java.text.SimpleDateFormat; 
import java.util.Calendar; 
import java.util.Date; 
import java.util.TimeZone; 

import org.joda.time.DateTimeZone; 
import org.junit.Before; 
import org.junit.Test; 

public class TimeTest { 
    Calendar nov6; 
    Calendar nov1; 
    Calendar nov12; 

    Calendar mar12; 
    Calendar mar14; 

    @Before 
    public void doBefore() { 
     // November 1st 2010, 9:00pm (DST is active) 
     nov1 = Calendar.getInstance(); 
     nov1.setTimeZone(TimeZone.getTimeZone("US/Arizona")); 
     nov1.set(Calendar.HOUR_OF_DAY, 21); 
     nov1.set(Calendar.MINUTE, 0); 
     nov1.set(Calendar.SECOND, 0); 
     nov1.set(Calendar.YEAR, 2010); 
     nov1.set(Calendar.MONTH, 10); // November 
     nov1.set(Calendar.DATE, 1); 

     // November 6st 2010, 9:00pm (DST is still active until early AM 
     // november 7th) 
     nov6 = Calendar.getInstance(); 
     nov6.setTimeZone(TimeZone.getTimeZone("US/Arizona")); 
     nov6.set(Calendar.HOUR_OF_DAY, 21); 
     nov6.set(Calendar.MINUTE, 0); 
     nov6.set(Calendar.SECOND, 0); 
     nov6.set(Calendar.YEAR, 2010); 
     nov6.set(Calendar.MONTH, 10); // November 
     nov6.set(Calendar.DATE, 6); 

     // November 12th 2010, 9:00pm (DST has ended) 
     nov12 = Calendar.getInstance(); 
     nov12.setTimeZone(TimeZone.getTimeZone("US/Arizona")); 
     nov12.set(Calendar.HOUR_OF_DAY, 21); 
     nov12.set(Calendar.MINUTE, 0); 
     nov12.set(Calendar.SECOND, 0); 
     nov12.set(Calendar.YEAR, 2010); 
     nov12.set(Calendar.MONTH, 10); // November 
     nov12.set(Calendar.DATE, 12); 

     // March 12th 2011, 9:00pm (DST has ended, will begin early a.m. march 
     // 13th) 
     mar12 = Calendar.getInstance(); 
     mar12.setTimeZone(TimeZone.getTimeZone("US/Arizona")); 
     mar12.set(Calendar.HOUR_OF_DAY, 21); 
     mar12.set(Calendar.MINUTE, 0); 
     mar12.set(Calendar.SECOND, 0); 
     mar12.set(Calendar.YEAR, 2010); 
     mar12.set(Calendar.MONTH, 2); // March 
     mar12.set(Calendar.DATE, 12); 

     // March 14th 2011, 9:00pm (DST has started) 
     mar14 = Calendar.getInstance(); 
     mar14.setTimeZone(TimeZone.getTimeZone("US/Arizona")); 
     mar14.set(Calendar.HOUR_OF_DAY, 21); 
     mar14.set(Calendar.MINUTE, 0); 
     mar14.set(Calendar.SECOND, 0); 
     mar14.set(Calendar.YEAR, 2010); 
     mar14.set(Calendar.MONTH, 2); // March 
     mar14.set(Calendar.DATE, 14); 
    } 

    @Test 
    public void testArizonaToPacific() { 
     System.out.println("=== November 1st, Expected Result (0 hour) ==="); 
     timeTestJava(nov1.getTime(), "US/Arizona", "US/Pacific"); 
     timeTestJoda(nov1.getTime(), "US/Arizona", "US/Pacific"); 
     System.out.println("=======================================\n"); 

     System.out.println("=== November 6th, Expected Result (0 hour) ==="); 
     timeTestJava(nov6.getTime(), "US/Arizona", "US/Pacific"); 
     timeTestJoda(nov6.getTime(), "US/Arizona", "US/Pacific"); 
     System.out.println("=======================================\n"); 

     System.out.println("=== November 12th, Expected Result (-1 hour) ==="); 
     timeTestJava(nov12.getTime(), "US/Arizona", "US/Pacific"); 
     timeTestJoda(nov12.getTime(), "US/Arizona", "US/Pacific"); 
     System.out.println("=======================================\n"); 

     System.out.println("=== March 12th, Expected Result (-1 hour) ==="); 
     timeTestJava(mar12.getTime(), "US/Arizona", "US/Pacific"); 
     timeTestJoda(mar12.getTime(), "US/Arizona", "US/Pacific"); 
     System.out.println("=======================================\n"); 

     System.out.println("=== March 14th, Expected Result (0 hour) ==="); 
     timeTestJava(mar14.getTime(), "US/Arizona", "US/Pacific"); 
     timeTestJoda(mar14.getTime(), "US/Arizona", "US/Pacific"); 
     System.out.println("=======================================\n"); 
    } 

    @Test 
    public void testEasternToPacific() { 
     System.out.println("=== November 1st, Expected Result (-3 hour) ==="); 
     timeTestJava(nov1.getTime(), "US/Eastern", "US/Pacific"); 
     timeTestJoda(nov1.getTime(), "US/Eastern", "US/Pacific"); 
     System.out.println("=======================================\n"); 

     System.out.println("=== November 6th, Expected Result (-3 hour) ==="); 
     timeTestJava(nov6.getTime(), "US/Eastern", "US/Pacific"); 
     timeTestJoda(nov6.getTime(), "US/Eastern", "US/Pacific"); 
     System.out.println("=======================================\n"); 

     System.out.println("=== November 12th, Expected Result (-3 hour) ==="); 
     timeTestJava(nov12.getTime(), "US/Eastern", "US/Pacific"); 
     timeTestJoda(nov12.getTime(), "US/Eastern", "US/Pacific"); 
     System.out.println("=======================================\n"); 

     System.out.println("=== March 12th, Expected Result (-3 hour) ==="); 
     timeTestJava(mar12.getTime(), "US/Eastern", "US/Pacific"); 
     timeTestJoda(mar12.getTime(), "US/Eastern", "US/Pacific"); 
     System.out.println("=======================================\n"); 

     System.out.println("=== March 14th, Expected Result (-3 hour) ==="); 
     timeTestJava(mar14.getTime(), "US/Eastern", "US/Pacific"); 
     timeTestJoda(mar14.getTime(), "US/Eastern", "US/Pacific"); 
     System.out.println("=======================================\n"); 
    } 

    // print some output from the test 
    private void print(Date startTime, String text, String from, String to, 
      Date output) { 
     SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd hh:mm"); 

     System.out.println(text + ":"); 
     System.out.println("Converting " + sdf.format(startTime) + " from " 
       + from + " to " + to + "."); 
     long difference = output.getTime() - startTime.getTime(); 
     System.out.println("Result: " + sdf.format(output) + ". Change (" 
       + difference/1000/60/60 + " hour).\n"); 
    } 

    // wrapper around joda test 
    private void timeTestJoda(Date startTime, String from, String to) { 
     Date output = convertJodaOld(startTime, TimeZone.getTimeZone(from), 
       TimeZone.getTimeZone(to)); 
     print(startTime, "joda", from, to, output); 
    } 

    // wrapper around java test 
    private void timeTestJava(Date startTime, String from, String to) { 
     Date output = convertJava(startTime, TimeZone.getTimeZone(from), 
       TimeZone.getTimeZone(to)); 
     print(startTime, "java", from, to, output); 
    } 

    // Joda implementation, works before and after DST change, but not during 
    // the period from 2am-7am UTC on the day of the change 
    public Date convertJodaOld(Date dt, TimeZone from, TimeZone to) { 
     DateTimeZone tzFrom = DateTimeZone.forTimeZone(from); 
     DateTimeZone tzTo = DateTimeZone.forTimeZone(to); 

     Date utc = new Date(tzFrom.convertLocalToUTC(dt.getTime(), false)); 
     Date convertedTime = new Date(tzTo.convertUTCToLocal(utc.getTime())); 
     return convertedTime; 
    } 

    // Java implementation. Works. 
    public Date convertJava(Date dt, TimeZone from, TimeZone to) { 
     long fromOffset = from.getOffset(dt.getTime()); 
     long toOffset = to.getOffset(dt.getTime()); 

     long convertedTime = dt.getTime() - (fromOffset - toOffset); 
     return new Date(convertedTime); 
    } 
} 

감사

여기에 제공된 테스트의 출력 (11 월 6 일에 대한 항목이 오류을 설명)입니다!

답변

4

'US/Arizona'를 사용하지 마십시오. 사용되지 않습니다.

사용 '미국/피닉스'

'미국/태평양'에 간다 동일한 사용 '미국/로스 엔젤레스는'대신.

+0

당신이 제안한 시간대를 사용하는 것은 테스트 결과에 영향을 미치지 않지만, 잘 알고 있습니다. 미국/* 시간대에 대한 정보에 대한 링크가 있습니까? – samspot

+1

@samspot. 다음은 '공식'목록 -> http://en.wikipedia.org/wiki/List_of_tz_database_time_zones입니다. 이것은 다소 비공식적 인 정보입니다 -> http://www.timezoneconverter.com/cgi-bin/zoneinfo.tzc?s=default&tz=US/Pacific –

+0

@samspot. 내게 당신이 실제로 조다 시간을 사용하지 않는 것처럼 보입니다. DateTime 객체를 생성하고 여전히 문제가 있는지 확인하십시오. 필자는 코드 전체에서 DateTime을 사용하고 있으며 표준/주간 변경 사항이 시스템에서 중요하기 때문에이를 테스트했습니다. Joda 시간 클래스는 항상 올바른 결과를 반환했습니다. –

관련 문제