2013-02-21 145 views
7

我有一個String類型的時間戳,我試圖將其轉換爲雙(並找到結果單位爲秒),這裏是我做了什麼:SimpleDateFormat.parse()。getTime()返回一個不正確的(負數)值爲什麼?

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); 

的問題是,我得到一個值如-2722.515,我不知道爲什麼。

爲什麼它是負面的?

代碼有問題嗎?

當我將此時間戳轉換爲mm ss S與實際時間不匹配,這似乎是另一個問題!

回答

11

這是一個時區差異問題。

由於您只指定分鐘和秒鐘,日期將在1 Jan 1970 00:mm:ssmmss是當前時間的分鐘和秒鐘)。

我簡化您的例子:

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); 

打印出來,應該是GMT的從本地時區偏移的小時。

這樣做的原因是:

SimpleDateFormat是語言環境敏感,所以dateFormat.parse(timeStamp)將返回創建Date對象爲給定的時間段(默認爲本地時區)。然後getTime()midnight 1 Jan 1970 **GMT**獲得毫秒數。因此,該值將被本地時區距離GMT多遠所抵消。

如何解決此問題:

您可以通過設置parsedateFormat對象的時區修復它被稱爲如下:

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

它是可能是SimpleTimeFormat類嘗試兌現當前的時區設置,這需要將時間轉換成1970年1月1日00:mm:ss之前的某個時間。由於時代會在時間之後(並且在那裏也存在雙重投射,這沒有幫助),所以它可能會漂移到小範圍的內部無效值中,導致外部無效值。你可能會把它稱爲一個錯誤,但很難讓它對其聲明的有效範圍以外的時間負責。 – 2013-02-21 14:36:19

+0

@EdwinBuck編輯。 – Dukeling 2013-02-21 15:10:02

+0

非常感謝Dukeling :)它現在完美運行... – user2052015 2013-02-21 15:39:04

1

---實際上,有一個更好的方法來做到這一點,但如果你想使用日期,跳到編輯前的答案---

日期實際上並沒有做你想做的事情,這似乎是一個外部的時間計算實際上需要選擇真實世界日曆的時間。

爲了避免所有日期爲了跟上公曆而必須做的惡劣的特殊處理,你最好寫自己的班級。這種特殊處理包括(但不限於)時區的認識,夏令,宣稱「跳過天」,閏秒,閏年等

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(); 
} 

這種解決方案可能看起來就像是重新發明輪子,但真的是避免使用八角形作爲車輪。日期的行爲似乎並不是你想要的,儘管你可能會讓日期適用於某些有限範圍的值。

如果你想得到真正的幻想,你可以使上述的實現可比較等,但是,我會建議反對的東西。在施工後不要提供更新方法,因爲這會迫使一些相當不好的重新計算,並使代碼更難以維護。而應提供返回新TimeOnlys以迴應您希望實施的操作的方法。

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

此外,不要實現你不打算使用。未使用的代碼往往是臭蟲的肥沃土壤。

當然,所有「時間」事物的股票答案都考慮使用JodaTime,它區分了所有不同類型的時間度量。但是,對於這樣的小問題,就像使用坦克殺死一隻螞蟻一樣。

---預編輯答案---

沒有時間完整的規範(年,月,日,時,分,秒,毫秒)的時間值作爲第一步格式化將會有很多未指定的字段。這些領域的進展可能會是垃圾。

然後getTime()作用於整個Date對象將有效字段和垃圾翻譯成值,其中垃圾甚至可以修改有效值(96秒= 1分36秒,因爲字段相互作用)。

最好的辦法是將所有「僅限時間」日期初始化爲一個已知日期,因此當您進行比較和數學運算時(即,3 11 23> ?),您會得到一致的結果(是的, 3 11 23>1 02 10,因爲它實際上是2013 02 10 00 03 11 23>2013 02 10 00 03 11 23和不2013 02 10 00 03 11 23相比2000 02 10 00 03 11 23

當選擇天使用,避免相鄰2月29日天,天是鄰近夏令換檔等

+0

當我這樣做就像你說的那樣我得到的結果像1.207806075005E9 但我需要的是在幾秒鐘內找到它,然後減去從以前的時間戳,因此我可以找到對話時間。 – user2052015 2013-02-21 14:06:11

相關問題