왜 이 두 번을 빼면 이상한 결과가 나올까요?
다음 프로그램을 실행하면 두 개의 날짜 문자열이 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+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
유효한 개념이라고 가정하기 때문에 다른 라이브러리가 이러한 인위적인 전환을 도입할 필요가 없습니다.
현지 표준시가 일요일인 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:08
Asia/Shanghai
, 1927-12-31 23:54:07
따라서 사용하는 오프셋에 따라 1초의 차이와 5분 53초의 차이가 있습니다.
일반적인 1시간 서머타임(서머타임)이 아닌 이 약간의 오프셋은 문제를 약간 모호하게 합니다.
2013a 타임존 데이터베이스 업데이트로 이 중단이 몇 초 일찍 이동되었지만 그 효과는 여전히 관찰할 수 있습니다.
★★★★★java.time
Java 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초면 됩니다.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:59
1928-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을 사용하는 사용자에게 도움이 되었으면 합니다.
IMHO
Java에 널리 퍼져 있는 암묵적인 현지화는 가장 큰 설계 결함입니다.사용자 인터페이스용일 수도 있지만 솔직히 현재 사용자 인터페이스용으로 Java를 실제로 사용하고 있는 사용자에게는 프로그래머가 타깃이 아니기 때문에 현지화를 무시할 수 있는 IDE가 있습니다.다음과 같이 수정할 수 있습니다(특히 Linux 서버에서).
- export 출 export
LC_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시간 돌아갑니다.할 때 차이가 .3600
1 가초 、 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
'programing' 카테고리의 다른 글
Gson 인스턴스를 모델빈의 정적 필드로 사용해도 될까요(재사용)? (0) | 2022.08.01 |
---|---|
Vue 라우터에서 경로 입력 전에 인증 토큰이 유효한지 확인하는 중 (0) | 2022.07.30 |
Vue 2.0에서의 CSS 클래스 전환 (0) | 2022.07.29 |
URL 디코딩은 Java에서 어떻게 하나요? (0) | 2022.07.29 |
2개의 클래스에서 확장 (0) | 2022.07.29 |