etc./StackOverFlow

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

청렴결백한 만능 재주꾼 2021. 9. 25. 02:02
반응형

질문자 :Freewind


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


답변자 : Jon Skeet


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 이 유효한 개념으로 가정)에 의존하지 않으므로 다른 라이브러리는 이 인위적인 전환을 도입할 필요가 없습니다.



답변자 : Michael Borgwardt


현지 시간 불연속성 이 발생했습니다.

현지 표준시가 1928년 1월 1일 일요일 00:00:00에 도달하려 할 때 시계가 1927년 12월 31일 토요일 0:05:52 시간으로 역전되었습니다. 대신 현지 표준시 23:54:08

이것은 특별히 이상하지 않으며 정치적 또는 행정적 조치로 인해 시간대가 전환되거나 변경됨에 따라 한 번에 또는 다른 시기에 거의 모든 곳에서 발생했습니다.



답변자 : Raedwald


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

  • 가능하면 UTC로 날짜와 시간을 사용하십시오.
  • UTC로 날짜 또는 시간을 표시할 수 없는 경우 항상 시간대를 표시하십시오.
  • UTC로 입력 날짜/시간을 요구할 수 없는 경우 명시적으로 표시된 시간대를 요구하십시오.


답변자 : PatrickO


시간을 증가시킬 때 UTC로 다시 변환한 다음 더하거나 빼야 합니다. 표시용으로만 현지 시간을 사용하십시오.

이렇게 하면 몇 시간 또는 몇 분이 두 번 발생하는 기간을 걸을 수 있습니다.

UTC로 변환한 경우 1초를 추가하고 표시를 위해 현지 시간으로 변환합니다. 11:54:08 pm LMT - 11:59:59 pm LMT를 거친 다음 11:54:08 pm CST - 11:59:59 pm CST를 거치게 됩니다.



답변자 : Rajshri


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

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

그런 다음 결과가 다음과 같은지 확인합니다.

 1


답변자 : user1050755


미안하지만 시간의 불연속성이 조금 움직였다

2년 전 JDK 6 과 최근 업데이트 25의 JDK 7 .

배울 교훈: 디스플레이를 제외하고는 모든 비용을 들여 UTC가 아닌 시간을 피하십시오.



답변자 : Daniel C. Sobral


다른 사람들이 설명했듯이 거기에는 시간 불연속성이 있습니다. Asia/Shanghai 에서 1927-12-31 23:54:08 에 대한 두 가지 가능한 시간대 오프셋이 1927-12-31 23:54:08 에 대한 오프셋은 1927-12-31 23:54:07 . 따라서 사용되는 오프셋에 따라 1초 또는 5분 53초의 차이가 있습니다.

우리에게 익숙한 일반적인 1시간의 일광 절약 시간(서머 타임) 대신 오프셋의 약간의 이동은 문제를 약간 모호하게 만듭니다.

시간대 데이터베이스의 2013년 업데이트는 이 불연속성을 몇 초 더 일찍 옮겼지만 그 효과는 여전히 관찰할 수 있습니다.

Java 8의 새로운 java.time 패키지를 사용하면 이를 보다 명확하게 볼 수 있고 이를 처리하는 도구를 제공할 수 있습니다. 주어진:

 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초가 되고 durationAtLaterOffset 은 5분 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);

isOverlap()isGap() 메서드를 사용하여 전환이 해당 날짜/시간에 대해 둘 이상의 유효한 오프셋이 있는 중첩 또는 해당 날짜/시간이 해당 영역 ID에 유효하지 않은 간격 zot4 .

Java 8이 널리 사용 가능해지면 이러한 종류의 문제를 처리하거나 JSR 310 백포트를 채택하는 Java 7을 사용하는 사람들에게 이것이 도움이 되기를 바랍니다.



답변자 : user1050755


IMHO Java의 만연하고 암묵적인 현지화는 가장 큰 단일 설계 결함입니다. 이것은 사용자 인터페이스를 위한 것일 수 있지만 솔직히 프로그래머가 정확히 현지화 대상이 아니기 때문에 기본적으로 현지화를 무시할 수 있는 일부 IDE를 제외하고 오늘날 사용자 인터페이스에 Java를 실제로 사용하는 사용자입니다. 다음과 같은 방법으로 문제를 해결할 수 있습니다(특히 Linux 서버에서).

  • 내보내기 LC_ALL=C TZ=UTC
  • 시스템 시계를 UTC로 설정
  • 절대적으로 필요한 경우가 아니면 절대로 현지화된 구현을 사용하지 마십시오(예: 디스플레이 전용).

Java 커뮤니티 프로세스 구성원에게 다음을 권장합니다.

  • 기본값이 아닌 현지화 방법을 만들지만 사용자가 현지화를 명시적으로 요청해야 합니다.
  • UTF-8/UTCFIXED 기본값으로 사용하세요. 그것이 오늘날의 기본값이기 때문입니다. 이와 같은 스레드를 생성하려는 경우를 제외하고는 다른 작업을 수행할 이유가 없습니다.

내 말은, 전역 정적 변수가 반OO 패턴이 아닙니까? 기본적인 환경 변수가 제공하는 일반적인 기본값은 없습니다........



답변자 : new QOpenGLWidget


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

23:54:07 로 상하이에서 23:54:07 이었으나 5분 52초 후 다음날 00:00:00 으로 바뀌었고 현지 표준시가 다시 23:54:08 . 그렇기 때문에 두 시간의 차이는 예상대로 1초가 아닌 343초입니다.

시간은 미국과 같은 다른 곳에서도 엉망이 될 수 있습니다. 미국에는 일광 절약 시간제가 있습니다. 일광 절약 시간이 시작되면 시간이 1시간 앞으로 이동합니다. 그러나 잠시 후 서머타임이 종료되고 표준시대로 1시간 후퇴합니다. 그래서 때때로 미국의 시간을 비교할 때 그 차이는 1초가 아니라 3600

그러나 이러한 두 번의 변화에는 다른 점이 있습니다. 후자는 계속해서 변화하고 전자는 단지 변화일 뿐입니다. 그것은 다시 바뀌거나 같은 양만큼 다시 바뀌지 않았습니다.

디스플레이와 같이 UTC가 아닌 시간을 사용해야 하는 경우가 아니면 UTC를 사용하는 것이 좋습니다.



답변자 : Vlad


이 문제를 피하려면 시간을 증가시킬 때 UTC로 다시 변환한 다음 더하거나 빼야 합니다.

이렇게 하면 몇 시간 또는 몇 분이 두 번 발생하는 기간을 걸을 수 있습니다.

UTC로 변환한 경우 1초를 추가하고 표시를 위해 현지 시간으로 변환합니다. 11:54:08 pm LMT - 11:59:59 pm LMT를 거친 다음 11:54:08 pm CST - 11:59:59 pm CST를 거치게 됩니다.



출처 : Here


출처 : http:www.stackoverflow.com/questions/6841333/why-is-subtracting-these-two-times-in-1927-giving-a-strange-result">

반응형