为什么SimpleDateFormat.parse()。getTime()返回一个不正确的(负)值?

我有一个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,它区分所有不同类型的时间测量。 然而,对于像这样的小问题,它类似于使用坦克杀死ant。

---编辑前的答案---

如果没有完整的时间规范(年,月,日,小时,分钟,秒,毫秒),则在第一步中格式化的时间值将包含许多未指定的字段。 这些领域的内容可能是垃圾。

然后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日附近的天数,接近夏令时class次的天数等。