java - Joda Time - 计算两个日期之间的秒数会引发异常。

标签 java android datetime jodatime

我使用以下代码来计算两个日期之间的秒数差异:

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 知道如何解析和生成此类字符串(PeriodDuration 类)。虽然 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

当转向另一个方向时,要么:

关于java - Joda Time - 计算两个日期之间的秒数会引发异常。,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25204043/

相关文章:

python - 如何获取一天的第一个日期时间?

php - 为什么 PHP 中的日期时间到时间戳转换不起作用?

PHP `DateTime::days` 返回垃圾?

java - 如何从终端将我的 Gradle 项目作为 JAR 运行

ubuntu - apt-get 错误,在我尝试安装 'sun-java6-jdk' 和 jre 失败后

java - 为什么我不能覆盖 onConfigurationChanged?

java - Android grpc 失败异常

android - 调用 adapter.notifyDataSetChanged() 时丢失当前选择

java - 使用 Fragment 后退按钮 android

java - Java 小程序是否可以在线使用?