简体   繁体   English

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

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

I have a time-stamp of type String and I am trying to convert it to a double (and find the result in seconds) and here is what I have done: 我有一个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);

The problem is that I obtain a value such as -2722.515 and I don't know why. 问题是我获得了-2722.515这样的值,我不知道为什么。

Why is it negative? 它为什么是否定的?

Is there something wrong with the code? 代码有问题吗?

When I convert this time-stamp to mm ss S does not match with the real time and this seems to be another problem! 当我将此时间戳转换为mm ss S与实际时间不匹配,这似乎是另一个问题!

It's a time zone discrepancy issue. 这是一个时区差异问题。

Since you only specified the minute and second, the date will be on 1 Jan 1970 00:mm:ss ( mm and ss being the minutes and seconds of the current time). 由于您只指定了分钟和秒,因此日期将在1 Jan 1970 00:mm:ss1 Jan 1970 00:mm:ssmmss是当前时间的分钟和秒)。

I simplified your example to: 我将你的例子简化为:

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

The hour printed out should be GMT 's offset from the local time zone. 打印出来的小时应该是GMT与当地时区的偏差。

The reason for this is: 原因是:

SimpleDateFormat is locale-sensitive, so dateFormat.parse(timeStamp) will return create a Date object for a given time zone (the default is the local time zone). SimpleDateFormat是区域设置敏感的,因此dateFormat.parse(timeStamp)将返回为给定时区创建Date对象(默认为本地时区)。 Then getTime() gets the number of milliseconds from midnight 1 Jan 1970 **GMT** . 然后getTime()midnight 1 Jan 1970 **GMT**获得毫秒数midnight 1 Jan 1970 **GMT** So the value will be offset by how far the local time zone is from GMT . 因此,该值将被当地时区距GMT时间的距离所抵消。

How to fix it: 如何解决:

You could fix it by setting the time zone of the dateFormat object before parse is called as follows: 您可以通过在调用parse之前设置dateFormat对象的时区来修复它,如下所示:

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

--- Actually there's a much better way to do this, but if you want to use dates, skip to the pre-edit answer --- ---实际上有更好的方法可以做到这一点,但是如果你想使用日期,请跳到编辑前的答案---

Dates don't actually do what you want, which appears to be time calculations outside of an actual need to pick times off a real world calendar. 日期实际上并不是你想要的,这似乎是在实际需要从现实世界日历中挑选时间之外的时间计算。

You'd be much better off writing your own class, to avoid all the nasty special handling that Dates must do in order to keep up with the Gregorian Calendar. 你最好自己编写自己的课程,以避免日期必须做的所有令人讨厌的特殊处理,以便跟上格里高利历。 This special handling includes (but is not limited to) timezone awareness, daylight savings, declared "skipped days", leap seconds, leap years, etc. 这种特殊处理包括(但不限于)时区感知,夏令时,宣布的“跳过天数”,闰秒,闰年等。

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

This solution may seem like it is reinventing the wheel, but really it is avoiding the use of an octagon as a wheel. 这个解决方案似乎正在重新发明轮子,但实际上它避免使用八角形作为轮子。 Date's behavior doesn't seem to be what you want, although you could possibly make Date work for some limited range of values. 日期的行为似乎不是您想要的,尽管您可以使Date适用于某些有限范围的值。

If you want to get really fancy, you could make the above implement comparable, etc. However, I would advise against on thing. 如果你想得到真正的幻想,你可以使上述工具可比,等等。但是,我会建议反对的事情。 Don't provide update methods after construction, as this forces some pretty nasty recalculations and makes the code harder to maintain. 在构造之后不要提供更新方法,因为这会强制进行一些非常讨厌的重新计算并使代码更难维护。 Instead provide methods that return new TimeOnlys in response to the operations you wish to implement. 而是提供返回新TimeOnlys的方法,以响应您希望实现的操作。

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

Also, don't implement what you aren't going to use. 另外,不要实现你不会使用的东西。 Unused code tends to be fertile soil for bugs. 未使用的代码往往是错误的肥沃土壤。

And of course, the stock answer for all "time" things, consider using JodaTime, which differentiates all the different types of time measurement. 当然,股票回答所有“时间”的事情,考虑使用JodaTime,它区分所有不同类型的时间测量。 However, for just a small problem like this, it's akin to using a tank to kill an ant. 然而,对于像这样的小问题,它类似于使用坦克杀死蚂蚁。

--- The pre-edit answer --- ---编辑前的答案---

Without a full specification of the time (year, month, day, hour, minute, second, milliseconds) your time value as formatted in the first step will have lots of fields that are not specified. 如果没有完整的时间规范(年,月,日,小时,分钟,秒,毫秒),则在第一步中格式化的时间值将包含许多未指定的字段。 What goes in those fields will likely be garbage. 这些领域的内容很可能是垃圾。

Then getTime() acts on the entire Date object translating both the valid fields and the garbage into a value, where the garbage may even modify the valid values (96 sec = 1 minute and 36 seconds, as the fields interact). 然后getTime()作用于整个Date对象,将有效字段和垃圾转换为值,其中垃圾甚至可以修改有效值(96秒= 1分36秒,因为字段交互)。

The best way to go about this is to have all your "time only" Dates initialized to one known day, so when you do comparisons and math operations (is, 3 11 23 > 1 02 10 ?) you get consistent results (yes, 3 11 23 > 1 02 10 , because it is actually 2013 02 10 00 03 11 23 > 2013 02 10 00 03 11 23 and not 2013 02 10 00 03 11 23 compared to 2000 02 10 00 03 11 23 解决这个问题的最佳方法是将所有“仅限时间”的日期初始化为一个已知的日期,因此当您进行比较和数学运算时(是, 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

When selecting the day to use, avoid days adjacent to Feb 29th, days that are near daylight savings shifts, etc. 选择使用日期时,请避开2月29日附近的天数,接近夏令时的天数等。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM