문제
두 개의 다른 형식으로 제공 될 수있는 두 타임 스탬프 사이의 지속 시간을 계산하기 위해 다음 코드를 만들었습니다.
public class dummyTime {
public static void main(String[] args) {
try {
convertDuration("2008-01-01 01:00 pm - 01:56 pm");
convertDuration("2008-01-01 8:30 pm - 2008-01-02 09:30 am");
} catch (Exception e) {
e.printStackTrace();
}
}
private static String convertDuration(String time) throws Exception {
String ts[] = time.split(" - ");
SimpleDateFormat formatNew = new SimpleDateFormat("HH:mm");
Date beg, end;
String duration = null;
beg = getDateTime(ts[0]);
end = getDateTime(ts[1], beg);
duration = formatNew.format(end.getTime() - beg.getTime());
System.out.println(duration + " /// " + time + " /// " + beg + " /// "
+ end);
return duration;
}
private static Date getDateTime(String dateTime) throws ParseException {
DateFormat formatOldDateTime = new SimpleDateFormat(
"yyyy-MM-dd hh:mm aa");
DateFormat formatOldTimeOnly = new SimpleDateFormat("hh:mm aa");
Date date = null;
try {
date = formatOldDateTime.parse(dateTime);
} catch (ParseException e) {
date = formatOldTimeOnly.parse(dateTime);
}
return date;
}
private static Date getDateTime(String dateTime, Date orig)
throws ParseException {
Date end = getDateTime(dateTime);
if (end.getYear() == 70) {
end.setYear(orig.getYear());
end.setMonth(orig.getMonth());
end.setDate(orig.getDate());
}
return end;
}
}
그것이 생성하는 출력은 다음과 같습니다.
01:56 /// 2008-01-01 01:00 pm - 01:56 pm /// Tue Jan 01 13:00:00 CET 2008 /// Tue Jan 01 13:56:00 CET 2008
14:00 /// 2008-01-01 8:30 pm - 2008-01-02 09:30 am /// Tue Jan 01 20:30:00 CET 2008 /// Wed Jan 02 09:30:00 CET 2008
내 질문은 다음과 같습니다.
- 결과가 항상 잘못된 이유 (항상 +1h)?
- 하루가없는 타임 스탬프를 식별하는 더 좋은 방법은 무엇입니까? == 70은 좋아 보이지 않으며 GetDay & SetDay 기능도 더 이상 사용되지 않습니다.
많은 고마워요,이 문제는 몇 시간 동안 나를 미치게 만들었습니다.
해결책
내 컴퓨터에서는 GMT+2에 있고 아마도 GMT+1에 있기 때문에 2 시간 씩 꺼져 있습니다. 주목하십시오
formatNew.format(end.getTime() - beg.getTime());
날짜를 받고, 즉, 56 분을 1970-01-01-00 : 56 : 00 GMT+1으로 취급합니다. 이것을 빨리 고치려면 전화하십시오formatNew.setTimeZone( TimeZone.getTimeZone( "GMT" ) );
두 번째 항목의 경우 Format-Yyyy-MM-DD가 실패했는지 확인할 수 있습니다 (구문 분석 오류를 포착 함). 이는 연도가 없다는 것을 알고있는 방법입니다.
다른 팁
당신은 시간과 시간의 시간이 아닌 시간을 포맷합니다. 겨울에는 CET 타임 존 (Central European Time)에있는 것처럼 UTC와 1 시간이 다릅니다 ( "GMT").
당신은 아마도 사용하고 싶을 것입니다 Calendar
대신에 Date
. 또는 조다-시간.
간단한 답변 : DATE가없는 시간을 나타내는 형식 값에 SimpleDateFormat을 사용하는 것은 부적절합니다.
더 긴 답변 : Java Time 값은 "Epoch"이후 밀리 초 수입니다. 1970 년 1 월 1 일 자정, UTC.
SimpledateFormat은 유효한 타임 스탬프를 제공한다고 가정하고 날짜와 시간으로 현지화 된 변환을 적용합니다. 나는 당신의 로케일이 GMT (Continental Europe)에서 1 시간 떨어진 곳이라고 생각합니다. 그래서 당신은 1 시간 쉬운 결과를보고 있습니다.
TimeZone GMT를 설정하여 SimpledateFormat을 속일 수 있지만 명시 적 수학을 사용하여 지속 시간을 표시하는 것이 좋습니다.
int duration = 90;
System.out.printf("%02d:%02d", duration / 60, duration % 60);
첫째, 예제 문자열은 일관성이 없습니다. 8:30 pm
패딩 0이 없습니다. 나는 그것이 오타라고 가정하고 08:30 pm
.
바람직하지 않은 문자열 형식
그건 그렇고, 이러한 입력 문자열 형식은 바람직하지 않습니다. - 훨씬 더 좋은 방법은 표준을 사용하는 것입니다 ISO 8601 형식. -M/PM이있는 12 시간 시계는 번거 롭습니다. 표준 형식은 시간 0-23 시간으로 24 시간 시계를 사용합니다.
- 간격에 대한 표준 표기법은 슬래시로 분리 된 날짜 시간 문자열 쌍입니다. 2008-01-01T13:00/2008-01-01T13:56
.
입력 문자열에는 또 다른 심각한 문제가 있습니다. UTC에서 오프셋 또는 시간대. 오프셋 또는 시간대가 없으면 일반적인 24 시간을 가정 할 때 돌아와야합니다. 이것은 일광 절약 시간 (DST)과 같은 이상을 무시하여 23 시간 또는 25 시간 동안 일할 수 있습니다.
들어오는 문자열을위한 시간대를 알고 있다면, 올바른 결과를 얻기 위해 두 번째 인수로 전달하십시오.
Java.Time
이 질문은 꽤 오래되었습니다. 그 이후로 Java는 귀찮은 오래된 날짜 시간 수업을 대체했습니다 (Date
, Calendar
, 최신 Java.Time 클래스와 함께 등. 아래 예제 코드에서 Java.Time을 사용합니다.
예제 수업
다음은 질문에 주어진대로 이러한 문자열을 처리하기위한 완전한 수업입니다. ㅏ Duration
생산되었다.
package javatimestuff;
import java.time.Duration;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.ZoneId;
import java.time.ZoneOffset;
import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;
import java.time.format.DateTimeParseException;
import java.util.Locale;
/**
*
* @author Basil Bourque
*/
public class DurationProcessor {
static final int SHORT = 30;
static final int LONG = 41;
static final DateTimeFormatter FORMATTER_LOCALDATETIME = DateTimeFormatter.ofPattern ( "uuuu-MM-dd hh:mm a" );
static final DateTimeFormatter FORMATTER_LOCALTIME = DateTimeFormatter.ofPattern ( "hh:mm a" );
static public Duration process ( String input ) {
return DurationProcessor.process ( input , ZoneOffset.UTC );
}
static public Duration process ( String input , ZoneId zoneId ) {
Duration d = Duration.ZERO; // Or maybe null. To be generated by the bottom of this code.
if ( null == input ) {
// …
System.out.println ( "ERROR - Passed null argument." );
return d;
}
if ( input.length () == 0 ) {
// …
System.out.println ( "ERROR - Passed empty string as argument." );
return d;
}
String inputModified = input.toUpperCase ( Locale.ENGLISH ); // Change `am` `pm` to `AM` `PM` for parsing.
String[] parts = inputModified.split ( " - " );
String inputStart = parts[ 0 ]; // A date-time sting.
String inputStop = parts[ 1 ]; // Either a date-time string or a time-only string (assume the same date).
ZonedDateTime start = null; // To be generated in this block of code.
try {
LocalDateTime ldt = LocalDateTime.parse ( inputStart , DurationProcessor.FORMATTER_LOCALDATETIME );
start = ldt.atZone ( zoneId );
} catch ( DateTimeParseException e ) {
// …
System.out.println ( "ERROR - The start failed to parse. inputStart: " + inputStart );
return d;
}
ZonedDateTime stop = null; // To be generated in this block of code.
switch ( input.length () ) {
case DurationProcessor.SHORT: // Example: "2008-01-01 01:00 pm - 01:56 pm"
try {
LocalTime stopTime = LocalTime.parse ( inputStop , DurationProcessor.FORMATTER_LOCALTIME );
stop = ZonedDateTime.of ( start.toLocalDate () , stopTime , zoneId );
} catch ( DateTimeParseException e ) {
// …
System.out.println ( "ERROR - The stop time failed to parse." );
return d;
}
break;
case DurationProcessor.LONG: // "2008-01-01 8:30 pm - 2008-01-02 09:30 am"
try {
LocalDateTime ldt = LocalDateTime.parse ( inputStop , DurationProcessor.FORMATTER_LOCALDATETIME );
stop = ldt.atZone ( zoneId );
} catch ( DateTimeParseException e ) {
// …
System.out.println ( "ERROR - The stop date-time failed to parse." );
return d;
}
break;
default:
// …
System.out.println ( "ERROR - Input string is of unexpected length: " + input.length () );
break;
}
d = Duration.between ( start , stop );
return d;
}
public static void main ( String[] args ) {
// Run with out time zone (assumes UTC).
Duration dShort = DurationProcessor.process ( "2008-01-01 01:00 pm - 01:56 pm" );
System.out.println ( "dShort: " + dShort );
Duration dLong = DurationProcessor.process ( "2008-01-01 08:30 pm - 2008-01-02 09:30 am" );
System.out.println ( "dLong: " + dLong );
// Run with specified time zone.
ZoneId z = ZoneId.of ( "America/Montreal" );
Duration dShortZoned = DurationProcessor.process ( "2008-01-01 01:00 pm - 01:56 pm" , z );
System.out.println ( "dShortZoned: " + dShortZoned );
Duration dLongZoned = DurationProcessor.process ( "2008-01-01 08:30 pm - 2008-01-02 09:30 am" , z );
System.out.println ( "dLongZoned: " + dLongZoned );
}
}
참고 main
클래스 내의 방법 예를 들어 사용법.
먼저 시간대를 지정하지 않고 한 쌍의 통화. 따라서 UTC와 24 시간이 사용됩니다.
Duration dShort = DurationProcessor.process ( "2008-01-01 01:00 pm - 01:56 pm" );
System.out.println ( "dShort: " + dShort );
Duration dLong = DurationProcessor.process ( "2008-01-01 08:30 pm - 2008-01-02 09:30 am" );
System.out.println ( "dLong: " + dLong );
의도 된 시간대를 지정하는 다른 통화 쌍.
ZoneId z = ZoneId.of ( "America/Montreal" );
Duration dShortZoned = DurationProcessor.process ( "2008-01-01 01:00 pm - 01:56 pm" , z );
System.out.println ( "dShortZoned: " + dShortZoned );
Duration dLongZoned = DurationProcessor.process ( "2008-01-01 08:30 pm - 2008-01-02 09:30 am" , z );
System.out.println ( "dLongZoned: " + dLongZoned );
라이브 코드
이 클래스가 실행되는 것을 참조하십시오 ideone.com의 라이브 코드.
dshort : pt56m
Dlong : PT13H
dshortzoned : pt56m
dlongzoned : PT13H
이 페이지의 다른 곳에서 언급 한 바와 같이, 출력 형식은 다음과 같은 시간 스타일을 사용합니다. 00:56
모호하고 혼란스럽고 피해야합니다. 그만큼 Duration
클래스는 대신 표준을 사용합니다 ISO 8601 지속 시간 형식. 위에서, 우리는 54 분과 13 분의 결과를 볼 수 있습니다.
Java.Time에 대해
그만큼 Java.Time 프레임 워크는 Java 8 이상에 내장되어 있습니다. 이 수업은 번거로운 오래된 것을 대체합니다 유산 다음과 같은 날짜 시간 수업 java.util.Date
, Calendar
, & SimpleDateFormat
.
그만큼 조다-시간 지금 프로젝트 유지 관리 모드, Java.Time 클래스.
자세한 내용은 오라클 튜토리얼. 많은 예와 설명에 대한 검색 스택 오버 플로우. 사양입니다 JSR 310.
Java.Time 수업을 어디에서 얻을 수 있습니까?
- Java SE 8 그리고 SE 9 그리고 나중에
- 내장.
- 번들 구현이있는 표준 Java API의 일부.
- Java 9는 사소한 기능과 수정 사항을 추가합니다.
- Java SE 6 그리고 SE 7
- Java.Time 기능의 대부분은 Java 6 & 7으로 백 포트되어 있습니다. Threeten-Backport.
- 기계적 인조 인간
- 그만큼 threetenabp 프로젝트 적응 Threeten-Backport (위에서 언급) 특히 Android의 경우.
- 보다 Threetenabp를 사용하는 방법….
그만큼 Threeten-extra 프로젝트는 추가 클래스로 Java.Time을 연장합니다. 이 프로젝트는 Java.Time에 향후 추가 할 수있는 근거입니다. 여기에서 유용한 수업을 찾을 수 있습니다 Interval
, YearWeek
, YearQuarter
, 그리고 더.