2013-02-21 15 views
7

mam czasu i daty z typu String i próbuję przekonwertować go na podwójne (i znaleźć wynik w sekundach) i tutaj jest to, co mam zrobić:Dlaczego metoda SimpleDateFormat.parse(). GetTime() zwraca niepoprawną (ujemną) wartość?

double mytimeStamp = 0; 

String timeStamp = new SimpleDateFormat(" mm ss S").format(new Date()); 

SimpleDateFormat dateFormat = new SimpleDateFormat(" mm ss S"); 

try { 
    mytimeStamp = ((double)dateFormat.parse(timeStamp).getTime())/1000; 
} catch (ParseException e1) { 
    // TODO Auto-generated catch block 
    e1.printStackTrace(); 
} 

System.out.println("timeStamp is: "+ mytimeStamp); 

Problemem jest to, że uzyskanie wartość taka jak -2722.515 i nie wiem dlaczego.

Dlaczego jest ujemny?

Czy coś jest nie tak z kodem?

Po konwersji tego znacznika czasu na mm ss S nie pasuje do czasu rzeczywistego i to wydaje się być innym problemem!

Odpowiedz

11

To problem rozbieżności w strefie czasowej.

Ponieważ podano tylko minuty i sekundy, data będzie podawana jako 1 Jan 1970 00:mm:ss (mm i ss jako minuty i sekundy bieżącego czasu).

I uproszczone swój przykład do:

String timeStamp = "00 00 00"; 
SimpleDateFormat dateFormat = new SimpleDateFormat("HH mm ss"); 
double hour = dateFormat.parse(timeStamp).getTime()/1000.0/60/60; 
System.out.println("hour is: "+ hour); 

Godzina drukowany powinien być GMT „s offsetowe z lokalnej strefy czasowej.

Powodem tego jest:

SimpleDateFormat locale jest wrażliwa, więc dateFormat.parse(timeStamp) powróci stworzyć Date obiektu dla danej strefy czasowej (domyślnie jest to lokalna strefa czasowa). Następnie getTime() pobiera liczbę milisekund od midnight 1 Jan 1970 **GMT**. Wartość zostanie więc skompensowana przez odległość lokalnej strefy czasowej od GMT.

Jak to naprawić:

Można to naprawić poprzez ustawienie strefy czasowej obiektu dateFormat przed parse nazywa się następująco:

dateFormat.setTimeZone(TimeZone.getTimeZone("GMT")); 
+0

jest prawdopodobnie klasa SimpleTimeFormat próbuje honorować aktualne ustawienia strefy czasowej, które wymagałyby przetłumaczenia czasu na coś przed "1 stycznia 1970 00: mm: ss". Ponieważ epoka byłaby wtedy "po" czasie (i tam też jest podwójna obsada, co nie pomaga), prawdopodobnie dryfował do niewielkiego zakresu wewnętrznych wartości nieważnych, co skutkowało nieprawidłowymi wartościami zewnętrznymi. Możesz to nazwać błędem, ale ciężko jest utrzymać go w odpowiedzialności za czasy poza jego deklarowanym skutecznym zasięgiem. –

+0

@EdwinBuck Edytowane. – Dukeling

+0

Dziękuję bardzo Dukeling :) działa idealnie teraz ... – user2052015

1

--- Faktycznie istnieje wiele lepiej sposób, aby to zrobić, ale jeśli chcesz użyć dat, przejdź do odpowiedzi przededycyjnej Daty w rzeczywistości nie rób tego, co chcesz, co wydaje się być obliczaniem czasu poza ctual trzeba wybrać razy z kalendarza świata rzeczywistego.

Znacznie lepiej byłoby napisać własną klasę, aby uniknąć wszystkich nieprzyjemnych specjalnych czynności, które musi spełniać Daty, aby nadążyć za kalendarzem gregoriańskim. Ta specjalna obsługa obejmuje (ale nie wyłącznie) świadomość strefa czasowa, czas letni, zadeklarował „pominięty dni”, skok sekund, lata przestępne, itd

public TimeOnly { 

    private long timestamp; 
    private int millis; 
    private int seconds; 
    ... etc ... 

    public TimeOnly(int hours, int minutes, int seconds, int millis) { 
    this.timestamp = millis + seconds * 1000L + minutes * 60000L + hours * 3600000L; 
    this.millis = millis; 
    this.seconds = seconds; 
    ... etc ... 
    } 

    private TimeOnly(long timestamp) { 
    this.timestamp = timestamp; 
    this.millis = timestamp % 1000; 
    this.seconds = timestamp % 60000L - this.millis; 
    ... etc ... 
    } 

    public long getTimestamp() { 
    return timestamp; 
    } 

    public int getMillis() { 
    return millis; 
    } 

    public int getSeconds() { 
    return seconds; 
    } 

    ... etc ... 
} 

public TimeFormatter { 

    public TimeFormatter() { 

    } 

    public String format(Time time) { 
    StringBuilder builder = new StringBuilder(); 
    builder.append(String.valueOf(time.getHours())); 
    builder.append(":"); 
    builder.append(String.valueOf(time.getMinutes())); 
    builder.append(":"); 
    builder.append(String.valueOf(time.getSeconds())); 
    builder.append("."); 
    if (time.getMillis() < 10) { 
     builder.append("00"); 
    } else if (time.getMillis() < 100) { 
     builder.append("0"); 
    } 
    builder.append(time.getMillis()); 
    return builder.toString(); 
} 

Takie rozwiązanie może wydawać się, że jest odkrywanie koła na nowo, ale tak naprawdę unika się używania ośmiokąta jako koła. Wygląda na to, że zachowanie daty nie jest tym, czego potrzebujesz, chociaż możliwe, że sprawisz, że praca będzie działać w ograniczonym zakresie wartości.

Jeśli chcesz się naprawdę spodobać, możesz sprawić, że powyższe narzędzie będzie porównywalne itp. Jednak odradzam. Nie udostępniaj metod aktualizacji po zakończeniu budowy, ponieważ wymuszają one pewne nieprzyjemne ponowne obliczenia i powodują, że kod jest trudniejszy do utrzymania. Zamiast tego podaj metody, które zwrócą nowe TimeOnlys w odpowiedzi na operacje, które chcesz zaimplementować.

public TimeOnly addSeconds(int value) { 
    int stamp = this.timestamp; 
    stamp += value * 60000L; 
    if (stamp < timestamp) { 
    throw new Excepton("overflow"); 
    } 
    return new TimeOnly(stamp); 
} 

Nie wdrażaj także tego, czego nie chcesz użyć. Niewykorzystany kod wydaje się być żyzną glebą dla błędów.

Oczywiście, odpowiedź na czas dla wszystkich "czas" rzeczy, należy rozważyć użycie JodaTime, który rozróżnia wszystkie różne rodzaje pomiaru czasu. Jednak w przypadku niewielkiego problemu takiego jak to, jest to podobne do używania czołgu do zabicia mrówki.

--- pre-edit odpowiedź ---

bez pełnej specyfikacji czasu (rok, miesiąc, dzień, godzina, minuta, sekunda, milisekundach) swoją wartość czasu jako sformatowane w pierwszym etapie będzie mieć wiele pól, które nie są określone. To, co dzieje się na tych polach, to prawdopodobnie śmieci.

Następnie getTime() działa na całym obiekcie Date, tłumacząc zarówno poprawne pola, jak i śmiecie na wartość, w której śmieci mogą nawet modyfikować prawidłowe wartości (96 sekund = 1 minuta i 36 sekund, w zależności od pól).

Najlepszym sposobem, aby go o to, aby mieć cały swój czas „tylko” Termin zainicjowany jednego znanego dni, więc jeśli zrobisz porównań i operacji matematycznych (jest 3 11 23>1 02 10?) Można uzyskać spójne wyniki (tak, 3 11 23>1 02 10, bo to jest rzeczywiście 2013 02 10 00 03 11 23>2013 02 10 00 03 11 23 i nie 2013 02 10 00 03 11 23 porównaniu 2000 02 10 00 03 11 23

Przy wyborze dzień w użyciu, unikać dni sąsiadujące Feb 29, dni, które są w pobliżu przesunięcia oszczędności światła dziennego itp

+0

Kiedy robię to tak jak powiedziałeś, mam wyniki jak 1.207806075005E9 , ale potrzebuję go znaleźć w kilka sekund, a następnie odjąć od poprzedniego znacznika czasu, a więc mogę znaleźć czas trwania okna dialogowego. – user2052015

Powiązane problemy