2013-02-21 601 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

相关问题