Java – Joda Time – Calculating the number of seconds between two dates throws an exception.

Joda Time – Calculating the number of seconds between two dates throws an exception…. here is a solution to the problem.

Joda Time – Calculating the number of seconds between two dates throws an exception.

I use the following code to calculate the difference in seconds between two dates:

long secondsBetween = (Seconds.secondsBetween(new LocalDate("1901-01-01"), new LocalDate()).getSeconds());

But I get the following exception:

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

Solution

int

As the other answers correctly point out, the problem is that you and Joda-Time are using int to handle seconds. A 32-bit int can only hold about 68 years of seconds.

If you insist on using seconds to track centuries, you must use 64-bit long instead of 32-bit int.

By the way, tracking time in seconds using a 32-bit int in Unix raises a real-world problem, knowing Year 2038 problem

Seconds are not used for long spans

As others have suggested, it is unusual to use seconds to track such a long span of time. If possible, you may want to reconsider that premise.

Another option: ISO 8601 standard provides Durations PnYnMnDTnHnMnMnS format, representing year, month, day, etc. Joda-Time knows how to parse and generate such strings(Period and Duration class). Although Joda-Time can only handle int numbers of seconds, it can handle larger seconds when rendered as strings in this ISO 8601 format, as shown in the following code example (PT3584908800S).

Milliseconds

Joda-Time tracks a count internally – epoch using milliseconds. Joda-Time provides a way to access these milliseconds as long values.

I usually recommend doing datetime work in milliseconds again. But in your case, it makes sense to convert to seconds as needed.

The beginning of the day

To calculate milliseconds, we need to use DateTime instead LocalDate .

Get into the habit of calling the method withTimeAtStartOfDay to get the first moment of the day. This time is usually 00:00:00, but not always because of daylight saving time or other unusual circumstances.

Time zone

Even for LocalDate, the time zone is critical. The date (and the first minute of the day) is determined by the time zone. A new day in Paris comes earlier than Montreal.

If you omit the time zone, the JVM’s current default time zone is used. It is usually best to clearly state and specify the desired time zone. I suspect it makes sense to use UTC for your purposes.

Duration

Joda-Time provides Duration class representing a span of time that is not related to the timeline (history of the universe).

Sample code

Sample code using 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.

Dump to the console.

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

Runtime.

history: 1901-01-01T00:00:00.000Z
today: 2014-08-08T00:00:00.000Z
duration: PT3584908800S
millis: 3584908800000
seconds: 3584908800

When turning in the other direction, either:

Related Problems and Solutions