문제

두 개의 다른 형식으로 제공 될 수있는 두 타임 스탬프 사이의 지속 시간을 계산하기 위해 다음 코드를 만들었습니다.

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

내 질문은 다음과 같습니다.

  1. 결과가 항상 잘못된 이유 (항상 +1h)?
  2. 하루가없는 타임 스탬프를 식별하는 더 좋은 방법은 무엇입니까? == 70은 좋아 보이지 않으며 GetDay & SetDay 기능도 더 이상 사용되지 않습니다.

많은 고마워요,이 문제는 몇 시간 동안 나를 미치게 만들었습니다.

도움이 되었습니까?

해결책

  1. 내 컴퓨터에서는 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" ) );

  2. 두 번째 항목의 경우 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 수업을 어디에서 얻을 수 있습니까?

그만큼 Threeten-extra 프로젝트는 추가 클래스로 Java.Time을 연장합니다. 이 프로젝트는 Java.Time에 향후 추가 할 수있는 근거입니다. 여기에서 유용한 수업을 찾을 수 있습니다 Interval, YearWeek, YearQuarter, 그리고 .

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top