프로그래밍 언어/JAVA

JAVA의 날짜 연산에서 이상한 결과가 나오는 이유

Rateye 2021. 7. 6. 10:18
728x90
반응형

 

질문 : 이 두 번을 빼면 (1927 년) 이상한 결과가 나오는 이유는 무엇입니까?

다음 프로그램을 실행하면 1 초 간격으로 시간을 참조하는 두 개의 날짜 문자열을 구문 분석하고 비교합니다.

public static void main(String[] args) throws ParseException {
    SimpleDateFormat sf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");  
    String str3 = "1927-12-31 23:54:07";  
    String str4 = "1927-12-31 23:54:08";  
    Date sDt3 = sf.parse(str3);  
    Date sDt4 = sf.parse(str4);  
    long ld3 = sDt3.getTime() /1000;  
    long ld4 = sDt4.getTime() /1000;
    System.out.println(ld4-ld3);
}

출력은 다음과 같습니다.

353

ld4-ld3 1 아니라 (1 초 차이에서 예상 353 입니까?

날짜를 1 초 후에 시간으로 변경하면 :

String str3 = "1927-12-31 23:54:08";  
String str4 = "1927-12-31 23:54:09";

그러면 ld4-ld31 됩니다.

자바 버전 :

java version "1.6.0_22"
                                Java(TM) SE Runtime Environment (build 1.6.0_22-b04)
                                Dynamic Code Evolution Client VM (build 0.2-b02-internal, 19.0-b04-internal, mixed mode)
                                
Timezone(`TimeZone.getDefault()`):
                                
	sun.util.calendar.ZoneInfo[id="Asia/Shanghai",
                              offset=28800000,dstSavings=0,
                              useDaylight=false,
                              transitions=19,
                              lastRule=null]
                                
Locale(Locale.getDefault()): zh_CN
답변

12 월 31 일 상하이의 시간대 변경입니다.

상하이 1927 년에 대한 자세한 내용은 이 페이지 를 참조하십시오. 기본적으로 1927 년 말 자정에 시계는 5 분 52 초로 거슬러 올라갑니다. 따라서 "1927-12-31 23:54:08"은 실제로 두 번 발생했으며 Java가 해당 로컬 날짜 / 시간에 대해 나중에 가능한 순간으로 파싱하는 것처럼 보입니다. 따라서 차이가 있습니다.

종종 이상하고 멋진 시간대 세계의 또 다른 에피소드입니다.

편집 : 그만 누르십시오! 역사 변경 ...

원래 질문은 TZDB 버전 2013a로 다시 빌드하면 더 이상 동일한 동작을 보여주지 않습니다. 2013a에서 결과는 358 초가되며 전환 시간은 23:54:08이 아니라 23:54:03입니다.

나는 Noda Time에서 단위 테스트 의 형태로 이와 같은 질문을 수집하고 있기 때문에 이것을 발견했습니다. 테스트는 이제 변경되었지만 단지 보여줄 것입니다. 심지어 과거 데이터조차 안전하지 않습니다.

편집 : 역사가 다시 변경되었습니다 ...

TZDB 2014f에서 변경 시간은 1900-12-31로 이동했으며 이제는 343 초에 불과합니다. 즉, tt+1 사이의 시간은 344 초입니다.

편집 : 1900 년 전환에 대한 질문에 대답하려면 ... Java 시간대 구현이 모든 시간대를 1900 UTC가 시작되기 전의 표준 시간으로 처리하는 것처럼 보입니다.

import java.util.TimeZone;

public class Test {
    public static void main(String[] args) throws Exception {
        long startOf1900Utc = -2208988800000L;
        for (String id : TimeZone.getAvailableIDs()) {
            TimeZone zone = TimeZone.getTimeZone(id);
            if (zone.getRawOffset() != zone.getOffset(startOf1900Utc - 1)) {
                System.out.println(id);
            }
        }
    }
}

위의 코드는 내 Windows 컴퓨터에서 출력을 생성하지 않습니다. 따라서 1900 년 초에 표준 오프셋 이외의 오프셋이있는 모든 시간대는 전환으로 간주됩니다. TZDB 자체는 그보다 일찍 되돌아가는 데이터를 가지고 있으며 "고정 된"표준 시간 ( getRawOffset 이 유효한 개념이라고 가정하는 것)에 대한 아이디어에 의존하지 않으므로 다른 라이브러리에서이 인공적인 전환을 도입 할 필요가 없습니다.

출처 : https://stackoverflow.com/questions/6841333/why-is-subtracting-these-two-times-in-1927-giving-a-strange-result
728x90
반응형