我希望获得Calendar对象实例的时间差异。由于某种原因,我在使用此功能时得到一个负数( -17666324.42 )。
对于overtimeHourLimit,我使用值8.
/*Date*/
Calendar mDateIn = Calendar.getInstance();
Calendar mDateOut = Calendar.getInstance();
mDateOut.set(mDateOut.YEAR, mDateOut.MONTH, mDateOut.DAY_OF_MONTH, mDateOut.HOUR_OF_DAY+10, mDateOut.MINUTE+25);
public String getRegHours(float overtimeHourLimit)
{
DecimalFormat twoDecimal = new DecimalFormat("0.##");
double totalHours = 0;
totalHours = (mDateOut.getTimeInMillis() - mDateIn.getTimeInMillis()) / (3.6f * Math.pow(10, 6));
if (totalHours <= overtimeHourLimit)
return twoDecimal.format(totalHours);
else return twoDecimal.format(overtimeHourLimit);
}
编辑:将其缩小到mDateOut.set()方法。 @HarshPandey在使用mDateOut.add()方法时发现,它正确地增加了时间。但是,我仍然难以理解为什么.set()方法首先不起作用。
edit2:https://github.com/MienTommy/CalendarTest我推出了一个示例代码,该代码应该等同于此问题中的代码段。唯一的区别是YEAR,MONTH,DAY_OF_MONTH常量在Android中不是静态的,但它应该没有区别,因为我用相同的实例初始化它们。
tl; dr .set()方法未按预期工作。
答案 0 :(得分:2)
问题的原因在于:
mDateOut.set(mDateOut.YEAR, mDateOut.MONTH, mDateOut.DAY_OF_MONTH, mDateOut.HOUR_OF_DAY + 10,
mDateOut.MINUTE + 25);
为了解释:
getTimeInMillis()获得了纪元:自1970年1月1日00:00:00以来的时间
和这个方法:
mDateOut.set()...
设置日历字段YEAR,MONTH,DAY_OF_MONTH,HOUR_OF_DAY和MINUTE的值。在日历实例....
但是您将传递类Calendar的常量作为参数,因此您将日期设置为 1970年1月1日00:00:00之前的值
考虑这样做:
mDateOut.set(mDateOut.YEAR, mDateOut.MONTH, mDateOut.DAY_OF_MONTH, mDateOut.HOUR_OF_DAY + 10,
mDateOut.MINUTE + 25);
和这样做是一样的....
mDateOut.set(1, 2, 5, 21, 37);
您可以通过执行以下操作验证新值:
System.out.println(new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(mDateOut.getTime()));
你会得到输出:
0001-03-05 21:37:40
因此 mDateOut 实际上是过去的日期...
结果否定:)
答案 1 :(得分:1)
试试这个:
long seconds = (mDateOut.getTimeInMillis() - mDateIn.getTimeInMillis()) / 1000;
double totalHours = (int) (seconds / 3600);
从我们的讨论看来,似乎是
mDateOut.add(Calendar.HOUR, 10)
mDateOut.add(Calendar.MINUTE, 25)
工作正常。
我最好的猜测是你可以使用set()
方法来设置时间,但不能在其中进行任何复杂的时间计算,并使用它来设置时间。并且在add()
方法中完美地处理了该计算。
答案 2 :(得分:0)
其他答案是正确的。但是你正在使用过时的类,这使得这项工作变得混乱,而且比必要的更困难。
java.time框架内置于Java 8及更高版本中。这些类取代了旧的麻烦日期时间类,例如java.util.Date
,.Calendar
和&amp; java.text.SimpleDateFormat
。
要了解详情,请参阅Oracle Tutorial。并搜索Stack Overflow以获取许多示例和解释。
大部分java.time功能都被反向移植到Java 6&amp; ThreeTen-Backport中的7,并在ThreeTenABP中进一步适应Android。
时区至关重要。如果未指定所需/预期的时区,则会隐式应用JVM的时区。该默认值可能随时发生变化。所以我建议你总是指定。
Instant
而不是.Calendar
,在需要时区时使用ZonedDateTime
,在需要UTC时使用Instant
。通常最好将UTC用于大多数业务逻辑,存储和数据交换。
Instant now = Instant.now();
Instant later = … ;
Duration
Duration
类以小时,分钟和秒为单位捕获经过的时间。
Duration duration = Duration.between( now , later );
Duration overtimeLimit = Duration.ofHours( 8 );
Boolean overtime = ( duration.compareTo( overtimeLimit ) > 0 );
BigDecimal
为获得小时的小数,我建议避免使用double
。作为floating-point数字,该类型会以速度的准确性为代价。
相反,请使用BigDecimal
来避免小数点右侧的错误额外数字。比例是小数点右边的位数。 RoundingMode
确定采取什么样的舍入方法,例如“小学校”四舍五入,你可能在小学里教过偏向于更大的数字,或“Bankers rounding”(HALF_EVEN
)更多当等距时,可以通过向偶数舍入。
使用TimeUnit
进行计算,而不是硬编码幻数,而使代码更加自我记录。
int scale = 2 ; // Decimal places to right of decimal point.
BigDecimal minutesInAnHour = BigDecimal.valueOf( TimeUnit.HOURS.toMinutes( 1 ) , scale ) ;
BigDecimal totalMinutes = BigDecimal.valueOf( duration.toMinutes() , scale ) ; // Calling `toMinutes` truncates any seconds and fractions of second that might be in the duration.
BigDecimal worked = totalMinutes.divide( minutesInAnHour , scale , RoundingMode.HALF_EVEN ) ;