【问题标题】:Why does this time unit conversion return zeroes?为什么这个时间单位转换返回零?
【发布时间】:2012-02-13 19:04:21
【问题描述】:

我在使用下面的代码时遇到问题。它将毫秒转换为月、日、小时和分钟。

long diffms = date2l - date1l; //The result here is in milliseconds; The value of date2l - date1l are different
long diff_minute = diffms / 60000;

long diff_hour = diff_minute / 60; float diff_minute_now = (diff_minute % 1) * 60; int dmn = (int) diff_minute_now;
long diff_day = diff_hour / 24; float diff_hour_now = (diff_hour % 1) * 24; int dhn = (int) diff_hour_now;
long diff_month = diff_day / 30; float diff_day_now = (diff_day % 1) * 30;  int ddn = (int) diff_day_now;   

diffe = new LabelField
("Remaining Time : " + Long.toString(diff_month) + " month(s) " 
                    + Integer.toString(ddn) + " day(s) " 
                    + Integer.toString(dhn) + " hour(s) "
                    + Integer.toString(dmn) + " minute(s)");
add(diffe);

为什么结果值全为零?

编辑: @BicycleDude 我将您的代码修改为:

long diffms = date2l - date1l;
long ts = diffms / 1000;

long mo = ts / 60 / 60 / 24 / 30;
long d = (ts - mo * 30 * 24 * 60 * 60) / (60 * 60 * 24);
long h = (ts - d * 24 * 60 * 60) / (60 * 60);
long m = (ts - h * 60 * 60) / 60;

但时间不工作

【问题讨论】:

  • date2ldate1l 使用什么值?如果date2l == date1l,你会期望所有的值都是0。
  • 这是日历中的时间,以毫秒为单位。它们是不同的。

标签: java math integer floating-point long-integer


【解决方案1】:

'anything % 1' 将返回 0。这可能不是您想要的。

  1. 您最初划分的变量是 long 类型。所以他们的结果也会很长。 (例如 12345 / 100 = 123 而不是 123.45)。
  2. 模运算符对整数除法的余数起作用。 (例如 12345 % 100 = 45)。
  3. 您提供的算法未按您预期的方式提取日、月、时、分、秒。它需要返工才能正确。

假设一个月有 31 天,我重新设计了公式:

long diffms = date2l - date1l;
long mo = (diffms / 1000 / 60 / 60 / 24 / 31);
long d = (diffms / 1000 / 60 / 60 / 24) % 31;
long h = (diffms / 1000 / 60 / 60) % 24;
long m = (diffms / 1000 / 60) % 60;
long s = (diffms / 1000) % 60;

【讨论】:

  • 好吧,假设 diff_minute 的值为 100,000。为了达到小时,我必须将它除以 60,结果将是 1667.67。 0.67 的值应该乘以 60 以获得分钟的最后一个值,对吗?那么这样做的方法不是 diff_minute % 1?
  • 没有。 x % y 将 x 除以 y,然后返回该操作的整数余数。 7 % 2 是 1,8 % 2 是 0。如果你想要 0.67 乘以 60,那就是 0.67 * 60。
  • 这就是我使用 % 1 的原因,因为余数将是十进制值。还是不是?
  • @Anthony 因为您的大多数变量都是长类型的,所以您已经删除了对您有用的精度。
  • Anthony,模运算符仅适用于整数余数。 i % 1 将永远是 0,因为 % 是在整数字段上定义的二元运算(我可能记错了我的数学)。无论如何,long 故事short,您不能使用模数并期望非整数值作为结果。对不起,糟糕的双关语。
【解决方案2】:

我的答案将基于代码的编辑部分,因为 BicycleDude 已经指出了模运算的问题。

long diffms = date2l - date1l; //difference in ms
long ts = diffms / 1000; //total difference in seconds

long mo = ts / 60 / 60 / 24 / 30; //(1)
long d = (ts - mo * 30 * 24 * 60 * 60) / (60 * 60 * 24); //follows on because of (1)
long h = (ts - d * 24 * 60 * 60) / (60 * 60); //follows on because of (1)
long m = (ts - h * 60 * 60) / 60; //follows on because of (1)

好吧,我认为会有多个问题,但我认为(认为,我可能遗漏了一些东西......)主要错误来自您对月份的计算,我在代码中由注释 (1) 表示。你无法像那样计算月份的差异。

为什么?如果差异超过一个月怎么办?您不需要除以 31 吗?或者如果它是闰年?如果是 2 月,您需要除以 29。由于整数除法不四舍五入或考虑小数,因此您的月差计算可能不准确。最好使用小时数的差异来计算天数的差异,然后从那里计算出月数的差异。 (编辑:我认为您还需要考虑我上面提到的因素,通过检查您的“起点”和“目标”日期来计算月差和天数差是,虽然我不太确定自己在这个阶段写它......)

由于您计算月差的方式有问题,并且您使用错误的值来计算天数的差,我认为这会导致错误传播到您的其他一些值(例如时差)。

编辑

好的,我对代码进行了一些修改。正如我之前提到的,您的月份计算很危险,并且影响了您的天数计算,这可能会在以后引入错误。

对于您在 cmets 中提供的示例,您的代码在天数上有 3 天的差异。 (示例为 2012 年 1 月 19 日至 2012 年 5 月 3 日)。我对 BicycleDude 的代码运行了这个,结果很好。

我将重新发布代码,我刚刚添加了一行以根据经过的小时数来查找天数。

long h = ts / 60 / 60; // hour part
long m = (ts - h * 60 * 60) / 60; // minute part
long s = (ts - h * 60 * 60 - m * 60); // second part
long d = h / 24;

如果你想让它读到“date2l 和 date1l 之间有w 天、x 小时、y 分钟和z 秒”,你可以这样做:

long date2l = Timestamp.valueOf("2012-05-03 05:30:10").getTime();
long date1l = Timestamp.valueOf("2012-01-19 00:00:00").getTime();
long diffms = date2l - date1l; //difference in ms
long diff_seconds = diffms / 1000; //total difference in seconds
long diff_mins = diff_seconds / 60; //total difference in minutes
long diff_hours = diff_mins / 60; //total difference in hours
long diff_days = diff_hours / 24; //total difference in days

long x = (diff_seconds - diff_days * 60 * 60 * 24) / (60 * 60);
long y = ((diff_seconds - (diff_hours * 60 * 60))) / 60;
long z = ((diff_seconds - (diff_mins * 60)));
long w = diff_days;

System.out.println(w + " " + x + " " + y + " " + z);

而且它似乎有效。

我还没有弄清楚月份部分,因为那更重要,但是是的。这个行得通吗?

【讨论】:

  • 是一样的。我得到了 13 天 0 小时 18720 分钟的结果。虽然不能说 ts 的价值,因为我自己也不知道。 date1l 和 date2l 取自日历函数。但我从今天(2012 年 1 月 19 日)算到 2012 年 2 月 1 日
  • 啊,好吧。让我重新检查一下代码,然后...我很确定我之前注意到的内容会成立,尽管它可能并不明显,因为您检查的日期相差不到一个月。
  • @blahman 我把今天放到 2012 年 5 月 3 日,它返回 102 天 0 小时 151200 分钟
  • 抱歉,这需要一段时间。我试图弄清楚如何进行转换,因为我遇到了心理障碍。我将在下一次编辑中尝试评论并使代码更简单。
  • yepp...我把 2012 年 1 月 19 日到 2012 年 2 月 1 日,它只显示 13 天 0 小时 o 分钟
【解决方案3】:

TimeUnit 类提供工厂方法来简化您的大部分工作:

import static java.util.concurrent.TimeUnit.*; 


// First, calculate the total difference in each unit
long diffDays = MILLISECONDS.toDays(diffMs);
long diffHours = MILLISECONDS.toHours(diffMs);
long diffMinutes = MILLISECONDS.toMinutes(diffMs);
long diffSeconds = MILLISECONDS.toSeconds(diffMs);

// Next, calculate the differences
long months = diffDays / 30;
long days = diffDays - 30 * months;
long hours = diffHours - DAYS.toHours(diffDays);
long minutes = diffMinutes - HOURS.toMinutes(diffHours);
long seconds = diffSeconds - MINUTES.toSeconds(diffMinutes);

【讨论】:

    猜你喜欢
    • 2018-05-30
    • 2012-12-17
    • 1970-01-01
    • 2011-10-11
    • 2015-11-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多