programing

왜 이 두 번을 빼면 이상한 결과가 나올까요?

javaba 2022. 7. 29. 23:58
반응형

왜 이 두 번을 빼면 이상한 결과가 나올까요?

다음 프로그램을 실행하면 두 개의 날짜 문자열이 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-ld3 되다1.


Java 버전:

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는 이를 해당 로컬 날짜/시간에서 가장 나중에 가능한 순간으로 해석하고 있는 것으로 보입니다.이 때문에 차이가 있습니다.

종종 이상하고 멋진 시간대의 또 다른 에피소드가 있을 뿐이다.

EDIT: 정지 누름!이력 변경...

원래 질문은 TZDB 버전 2013a로 재구성될 경우 더 이상 동일한 동작을 보여주지 않습니다.2013a의 경우 결과는 358초이며 전환 시간은 23:54:08이 아닌 23:54:03입니다.

노다 타임에서 이런 문제를 유닛 테스트 형식으로 수집하고 있기 때문에 알아차렸을 뿐입니다.이제 테스트는 변경되었지만, 과거 데이터조차 안전하지 않다는 것을 보여줍니다.

편집: 기록이 다시 변경되었습니다...

하지 않았습니다(은 1900-12-31입니다.t ★★★★★★★★★★★★★★★★★」t+1344번입니다. 슨슨말 인인?

편집: 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유효한 개념이라고 가정하기 때문에 다른 라이브러리가 이러한 인위적인 전환을 도입할 필요가 없습니다.

현지 시간 중단이 발생했습니다.

현지 표준시가 일요일인 1. 1928년 1월 00:00:00 시계는 토요일인 31일 토요일로 0:05:52시간 거꾸로 돌아갔습니다.1927년 12월 23:54:08 현지 표준시

이것은 특별히 이상한 일은 아니며 정치적 또는 행정적 조치로 인해 시간대가 바뀌거나 바뀌면서 한 때 또는 다른 때 거의 모든 곳에서 일어났다.

이 이상함의 교훈은 다음과 같습니다.

  • 가능한 경우 UTC 날짜 및 시간을 사용하십시오.
  • 날짜 또는 시간을 UTC로 표시할 수 없는 경우 항상 시간대를 지정합니다.
  • UTC 의 입력 일시를 필요로 할 수 없는 경우는, 명시적으로 지정한 타임 존을 요구합니다.

시간을 늘릴 때는 UTC로 다시 변환한 다음 더하기 또는 빼기를 수행해야 합니다.로컬 시간은 표시에만 사용합니다.

이렇게 하면 시간이나 분수가 두 번 발생하는 모든 기간을 걸을 수 있습니다.

UTC로 변환한 경우 매초를 더하고 로컬 시간으로 변환하여 표시합니다.오후 11:54:08 LMT - 11:59:59 LMT - 11:54:08 CST - 11:59:59 CST를 거칩니다.

각 날짜를 변환하는 대신 다음 코드를 사용할 수 있습니다.

long difference = (sDt4.getTime() - sDt3.getTime()) / 1000;
System.out.println(difference);

그리고 그 결과는 다음과 같습니다.

1

미안하지만, 시간 불연속성이 좀 더 심해진 것 같아요.

JDK 6은 2년 전에, JDK 7은 최근 업데이트 25에서 공개되었습니다.

교훈: 디스플레이를 제외하고 UTC 이외의 시간은 반드시 피하십시오.

다른 사람들이 설명하듯이, 거기에는 시간 불연속성이 있다.「2」의 존 에는, 2개의 오프셋이 .1927-12-31 23:54:08Asia/Shanghai, 1927-12-31 23:54:07따라서 사용하는 오프셋에 따라 1초의 차이와 5분 53초의 차이가 있습니다.

일반적인 1시간 서머타임(서머타임)이 아닌 이 약간의 오프셋은 문제를 약간 모호하게 합니다.

2013a 타임존 데이터베이스 업데이트로 이 중단이 몇 초 일찍 이동되었지만 그 효과는 여전히 관찰할 수 있습니다.

★★★★★java.timeJava 8의 패키지를 사용하면 이를 보다 명확하게 볼 수 있으며 이를 처리하기 위한 도구를 제공할 수 있습니다. ★★★★★★★:

DateTimeFormatterBuilder dtfb = new DateTimeFormatterBuilder();
dtfb.append(DateTimeFormatter.ISO_LOCAL_DATE);
dtfb.appendLiteral(' ');
dtfb.append(DateTimeFormatter.ISO_LOCAL_TIME);
DateTimeFormatter dtf = dtfb.toFormatter();
ZoneId shanghai = ZoneId.of("Asia/Shanghai");

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

ZonedDateTime zdt3 = LocalDateTime.parse(str3, dtf).atZone(shanghai);
ZonedDateTime zdt4 = LocalDateTime.parse(str4, dtf).atZone(shanghai);

Duration durationAtEarlierOffset = Duration.between(zdt3.withEarlierOffsetAtOverlap(), zdt4.withEarlierOffsetAtOverlap());

Duration durationAtLaterOffset = Duration.between(zdt3.withLaterOffsetAtOverlap(), zdt4.withLaterOffsetAtOverlap());

★★★★★★★★★★★★★★★.durationAtEarlierOffset 1초 1초면 됩니다.durationAtLaterOffset5시 53분

또한 이 두 오프셋은 동일합니다.

// Both have offsets +08:05:52
ZoneOffset zo3Earlier = zdt3.withEarlierOffsetAtOverlap().getOffset();
ZoneOffset zo3Later = zdt3.withLaterOffsetAtOverlap().getOffset();

하지만 이 두 가지는 다릅니다.

// +08:05:52
ZoneOffset zo4Earlier = zdt4.withEarlierOffsetAtOverlap().getOffset();

// +08:00
ZoneOffset zo4Later = zdt4.withLaterOffsetAtOverlap().getOffset();

같은 를 볼 수 .1927-12-31 23:59:591928-01-01 00:00:00 이 긴 컨버전스가 , 「」의 수 것은, 「」의

또 다른 접근 방법은 이행이 진행 중인지 확인하는 것입니다.다음과 같이 할 수 있습니다.

// Null
ZoneOffsetTransition zot3 = shanghai.getRules().getTransition(ld3.toLocalDateTime);

// An overlap transition
ZoneOffsetTransition zot4 = shanghai.getRules().getTransition(ld3.toLocalDateTime);

에 대해 개 또는 ID에 하지 않은 인지 여부를 할 수 이 경우 "/"/"를합니다.isOverlap() ★★★★★★★★★★★★★★★★★」isGap()zot4.

Java 8이 널리 보급되면 이러한 문제에 대처하는 데 도움이 되거나 JSR 310 백포트를 채택한 Java 7을 사용하는 사용자에게 도움이 되었으면 합니다.

IMHOJava에 널리 퍼져 있는 암묵적인 현지화는 가장 큰 설계 결함입니다.사용자 인터페이스용일 수도 있지만 솔직히 현재 사용자 인터페이스용으로 Java를 실제로 사용하고 있는 사용자에게는 프로그래머가 타깃이 아니기 때문에 현지화를 무시할 수 있는 IDE가 있습니다.다음과 같이 수정할 수 있습니다(특히 Linux 서버에서).

  • export 출 exportLC_ALL=C TZ=UTC
  • 시스템 클럭을 UTC로 설정합니다.
  • 꼭 필요한 경우가 아니면 현지화된 구현을 사용하지 않는다(표시 전용)

Java Community Process 멤버에게 추천하는 내용은 다음과 같습니다.

  • 는 디폴트가 아닌 현지화된 메서드를 만들지만 사용자가 현지화를 명시적으로 요구해야 합니다.
  • UTF-8/UTC현재 기본값이 FIXED로 되어 있기 때문에 대신 FIXED로 되어 있습니다.이런 스레드를 만들고 싶은 경우를 제외하고는 다른 작업을 할 이유가 없습니다.

내 말은, 제발, 글로벌 정적 변수들이 반(反)OO 패턴 아닌가요?그 외에는 기본적인 환경변수에 의해 제공되는 광범위한 디폴트......

다른 사람들이 말했듯이, 상하이에서는 1927년의 시간 변화입니다.

랬다다 였습니다.23:54:07 날, 52초, 52초, 52초, 52초입니다.00:00:00 후, '태양시'로 23:54:08그래서 두 시간의 차이는 예상대로 1초가 아니라 343초입니다.

미국과 같은 다른 곳에서도 시간은 흐트러질 수 있다.미국에는 서머타임이 있습니다.서머타임이 시작되면 시간은 1시간 앞으로 이동합니다.그러나 잠시 후 여름 시간이 종료되고 표준 시간대로 1시간 돌아갑니다.할 때 차이가 .36001 가초 、 1 가 1 1 1 。

하지만 이 두 번의 변화에는 뭔가 다른 점이 있다.후자는 끊임없이 변화하고 전자는 단지 변화일 뿐이다.그것은 같은 양으로 다시 바뀌거나 다시 바뀌지 않았다.

디스플레이와 같이 UTC 이외의 시간을 사용할 필요가 없는 한 UTC를 사용하는 것이 좋습니다.

이 문제를 방지하려면 시간을 늘릴 때 UTC로 다시 변환한 다음 더하기 또는 빼기를 수행해야 합니다.

이렇게 하면 시간이나 분수가 두 번 발생하는 모든 기간을 걸을 수 있습니다.

UTC로 변환한 경우 매초를 더하고 로컬 시간으로 변환하여 표시합니다.오후 11:54:08 LMT - 11:59:59 LMT - 11:54:08 CST - 11:59:59 CST를 거칩니다.

getTime()은 초수가 아닌밀리초를 반환하기 때문에 결과적으로 "1"이 될 수 없습니다(이 중 353밀리초는 공정한 포인트이지만 Date의 에폭은 1920년대가 아닌 1970년에 시작됩니다).cmmnt: 사용하고 있는 API 섹션은 대부분 사용되지 않는 것으로 간주됩니다.http://windsolarhybridaustralia.x10.mx/httpoutputtools-tomcat-java.html

언급URL : https://stackoverflow.com/questions/6841333/why-is-subtracting-these-two-times-in-1927-giving-a-strange-result

반응형