簡體   English   中英

為什么SimpleDateFormat.parse()。getTime()返回一個不正確的(負)值?

[英]Why does SimpleDateFormat.parse().getTime() return an incorrect (negative) value?

我有一個String類型的時間戳,我試圖將它轉換為double(並在幾秒鍾內找到結果),這就是我所做的:

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與實際時間不匹配,這似乎是另一個問題!

這是一個時區差異問題。

由於您只指定了分鍾和秒,因此日期將在1 Jan 1970 00:mm:ss1 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**獲得毫秒數midnight 1 Jan 1970 **GMT** 因此,該值將被當地時區距GMT時間的距離所抵消。

如何解決:

您可以通過在調用parse之前設置dateFormat對象的時區來修復它,如下所示:

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

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

日期實際上並不是你想要的,這似乎是在實際需要從現實世界日歷中挑選時間之外的時間計算。

你最好自己編寫自己的課程,以避免日期必須做的所有令人討厭的特殊處理,以便跟上格里高利歷。 這種特殊處理包括(但不限於)時區感知,夏令時,宣布的“跳過天數”,閏秒,閏年等。

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

這個解決方案似乎正在重新發明輪子,但實際上它避免使用八角形作為輪子。 日期的行為似乎不是您想要的,盡管您可以使Date適用於某些有限范圍的值。

如果你想得到真正的幻想,你可以使上述工具可比,等等。但是,我會建議反對的事情。 在構造之后不要提供更新方法,因為這會強制進行一些非常討厭的重新計算並使代碼更難維護。 而是提供返回新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 > 1 02 10 ?),您會獲得一致的結果(是的, 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 232000 02 10 00 03 11 23

選擇使用日期時,請避開2月29日附近的天數,接近夏令時的天數等。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM