我使用以下代码来计算两个日期之间的秒数差异:
long secondsBetween = (Seconds.secondsBetween(new LocalDate("1901-01-01"), new LocalDate()).getSeconds());
但是我得到以下异常:
08-08 18:21:27.345: E/AndroidRuntime(6972): java.lang.RuntimeException: Unable to start activity ComponentInfo{com.testbdr/com.testbdr.MainActivity}: java.lang.ArithmeticException: Value cannot fit in an int: 3584908800
08-08 18:21:27.345: E/AndroidRuntime(6972): at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2189)
08-08 18:21:27.345: E/AndroidRuntime(6972): at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2216)
08-08 18:21:27.345: E/AndroidRuntime(6972): at android.app.ActivityThread.access$600(ActivityThread.java:149)
08-08 18:21:27.345: E/AndroidRuntime(6972): at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1305)
08-08 18:21:27.345: E/AndroidRuntime(6972): at android.os.Handler.dispatchMessage(Handler.java:99)
08-08 18:21:27.345: E/AndroidRuntime(6972): at android.os.Looper.loop(Looper.java:153)
08-08 18:21:27.345: E/AndroidRuntime(6972): at android.app.ActivityThread.main(ActivityThread.java:5000)
08-08 18:21:27.345: E/AndroidRuntime(6972): at java.lang.reflect.Method.invokeNative(Native Method)
08-08 18:21:27.345: E/AndroidRuntime(6972): at java.lang.reflect.Method.invoke(Method.java:511)
08-08 18:21:27.345: E/AndroidRuntime(6972): at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:821)
08-08 18:21:27.345: E/AndroidRuntime(6972): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:584)
08-08 18:21:27.345: E/AndroidRuntime(6972): at dalvik.system.NativeStart.main(Native Method)
08-08 18:21:27.345: E/AndroidRuntime(6972): Caused by: java.lang.ArithmeticException: Value cannot fit in an int: 3584908800
08-08 18:21:27.345: E/AndroidRuntime(6972): at org.joda.time.field.FieldUtils.safeToInt(FieldUtils.java:206)
08-08 18:21:27.345: E/AndroidRuntime(6972): at org.joda.time.field.BaseDurationField.getDifference(BaseDurationField.java:141)
08-08 18:21:27.345: E/AndroidRuntime(6972): at org.joda.time.chrono.BaseChronology.get(BaseChronology.java:260)
08-08 18:21:27.345: E/AndroidRuntime(6972): at org.joda.time.base.BaseSingleFieldPeriod.between(BaseSingleFieldPeriod.java:105)
08-08 18:21:27.345: E/AndroidRuntime(6972): at org.joda.time.Seconds.secondsBetween(Seconds.java:124)
08-08 18:21:27.345: E/AndroidRuntime(6972): at com.testbdr.MainActivity.onCreate(MainActivity.java:27)
08-08 18:21:27.345: E/AndroidRuntime(6972): at android.app.Activity.performCreate(Activity.java:5020)
08-08 18:21:27.345: E/AndroidRuntime(6972): at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1080)
08-08 18:21:27.345: E/AndroidRuntime(6972): at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2153)
08-08 18:21:27.345: E/AndroidRuntime(6972): ... 11 more
最佳答案
int
正如其他答案正确指出的那样,问题是您和 Joda-Time 正在使用 int
来处理秒数。一个 32 位 int 只能容纳大约 68 年的秒数。
如果您坚持使用秒来跟踪几个世纪的时间,则必须使用 64 位 long
而不是 32 位 int
。
顺便说一句,在 Unix 中使用 32 位 int 以秒为单位跟踪时间提出了一个现实世界的问题,知道 Year 2038 problem .
秒不用于长时间跨度
正如其他人所建议的那样,使用秒来跟踪如此长的时间跨度是不寻常的。如果可能的话,您可能需要重新考虑该前提。
另一种选择:ISO 8601标准提供 Durations PnYnMnDTnHnMnS
的格式,表示年、月、日等。 Joda-Time 知道如何解析和生成此类字符串(Period 和 Duration 类)。虽然 Joda-Time 只能处理 int
numbers 秒数,但当以这种 ISO 8601 格式呈现为 strings 时,它可以处理更大的秒数,如下面的代码示例 (PT3584908800S
) 所示。
毫秒
Joda-Time 在内部跟踪一个计数- epoch使用毫秒。 Joda-Time 提供了将这些毫秒作为 long
值访问的方法。
我通常建议再次以毫秒为单位进行日期时间工作。但在您的情况下,根据需要转换为秒数是有道理的。
一天的开始
要计算毫秒,我们需要使用 DateTime而不是 LocalDate .
养成调用方法 withTimeAtStartOfDay
的习惯,以获取当天的第一时刻。这个时间通常是 00:00:00
但并不总是因为夏令时或其他异常情况。
时区
即使对于 LocalDate
,时区也是至关重要的。日期(和一天中的第一刻)由时区决定。巴黎的新一天比蒙特利尔来得早。
如果省略时区,将使用 JVM 当前的默认时区。通常最好明确说明并指定所需的时区。我怀疑出于您的目的,使用 UTC有道理。
时长
Joda-Time 提供 Duration表示与时间线(宇宙的历史)无关的时间跨度的类。
示例代码
使用 Joda-Time 2.4 的示例代码。
DateTime history = new DateTime( "1901-01-01", DateTimeZone.UTC ).withTimeAtStartOfDay(); // Technically, the call to withTimeAtStartOfDay is not necessary here as Joda-Time defaults to that for parsing a date-only string. But the call is a good habit and makes clear out intention.
DateTime today = new DateTime( DateTimeZone.UTC ).withTimeAtStartOfDay();
Duration duration = new Duration( history, today );
long millis = duration.getMillis(); // Use a long, not an int.
long seconds = ( millis / 1000L ); // Use a long, not an int. Maybe use BigDecimal or BigInteger if you want rounding.
转储到控制台。
System.out.println( "history: " + history );
System.out.println( "today: " + today );
System.out.println( "duration: " + duration );
System.out.println( "millis: " + millis );
System.out.println( "seconds: " + seconds );
运行时。
history: 1901-01-01T00:00:00.000Z
today: 2014-08-08T00:00:00.000Z
duration: PT3584908800S
millis: 3584908800000
seconds: 3584908800
当转向另一个方向时,要么:
- 将
long
秒数传递给静态方法Duration.standardSeconds
. - 将 ISO 8601 字符串传递给 constructor of Duration .
关于java - Joda Time - 计算两个日期之间的秒数会引发异常。,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25204043/