简体   繁体   English

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

[英]Joda Time - Calculation of seconds between two dates throws an exception.

I am using following code to calculate difference in seconds between two dates: 我使用以下代码来计算两个日期之间的秒数差异:

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

However I am getting 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

int

As the other answers correctly state, the problem is that you and Joda-Time are using an int to handle seconds. 正如其他答案正确陈述的那样,问题是你和Joda-Time正在使用int来处理秒数。 A 32-bit int can hold only about 68 years worth of seconds. 一个32位的int只能容纳大约68年的秒数。

If you insist on using seconds to track centuries of time, you must use a 64-bit long rather than an 32-bit int . 如果你坚持使用秒来跟踪几个世纪的时间,你必须使用64位long而不是32位int

By the way, the use in Unix of a 32-bit int to track time by seconds presents a real-world problem knows an the Year 2038 problem . 顺便说一句,在Unix中使用32位int来跟踪时间的秒数表示现实世界的问题知道2038年的问题

Seconds Not Used For Long Spans Of Time 秒不用于长时间跨度

As other suggest, using seconds to track such long spans of time is unusual. 正如其他人所说,使用秒来跟踪如此长的时间跨度是不寻常的。 You may want to rethink that premise, if possible. 如果可能的话,您可能想重新考虑这个前提。

One alternative: the ISO 8601 standard offers a Durations format of PnYnMnDTnHnMnS for number of years, months, days, and so on. 一种替代方案: ISO 8601标准提供PnYnMnDTnHnMnS持续时间格式,包括年,月,日等数量。 Joda-Time knows hows to parse and generate such strings ( Period and Duration classes). Joda-Time知道如何解析并生成这样的字符串( PeriodDuration类)。 While Joda-Time can only handle int numbers for seconds, it can handle larger number of seconds when presented as strings in this ISO 8601 format, as seen in code example below ( PT3584908800S ). 虽然约达时间只能处理int 号码秒,当作为字符串在该ISO 8601格式来呈现它可以处理更大的秒数,如以下代码示例( PT3584908800S )。

Milliseconds 毫秒

Joda-Time internally tracks a count-from- epoch using milliseconds. Joda-Time使用毫秒内部跟踪一个从纪元开始的计数。 Joda-Time offers methods to access those milliseconds as long values. Joda-Time提供了访问这些毫秒long值的方法。

I normally advise againt working in milliseconds for date-time work. 我通常建议你在几毫秒内完成日期工作。 But in your case it makes sense, converting to seconds as needed. 但在你的情况下,它是有道理的,根据需要转换为秒。

Start of Day 一天的开始

To calculate milliseconds, we'll need to use DateTime rather than LocalDate . 要计算毫秒数,我们需要使用DateTime而不是LocalDate

Make a habit of calling the method withTimeAtStartOfDay to get the first moment of the day. 养成用withTimeAtStartOfDay调用方法的习惯,以获得当天的第一个时刻。 This time is usually 00:00:00 but not always because of Daylight Saving Time or other anomalies. 这个时间通常是00:00:00但并不总是因为夏令时或其他异常。

Time Zone 时区

Time zone is crucial even for LocalDate . 即使对于LocalDate时区也是至关重要的。 The date (and first moment of day) is determined by the time zone. 日期(和一天的第一时刻)由时区决定。 A new day dawns earlier in Paris than it does in Montréal. 巴黎的新日早些时候比蒙特利尔更新。

If you omit the time zone, the JVM's current default time zone will be used. 如果省略时区,将使用JVM的当前默认时区。 Generally better to be explicit and specify the desired time zone. 通常更好地明确并指定所需的时区。 I suspect for your purposes, using UTC make sense. 我怀疑你的目的,使用UTC有意义。

Duration 持续时间

Joda-Time offers the Duration class to represent a span of time untied to the timeline (the history of the Universe). Joda-Time提供持续时间类来表示解开时间线(宇宙历史)的时间跨度。

Example Code 示例代码

Example code using Joda-Time 2.4. 使用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 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 );

When run. 跑步时

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

When going the other direction, either: 当走向另一个方向时,要么:

JodaTime has found the difference, which is 3584908800 seconds. JodaTime找到了差异,即3584908800秒。 But, it is unable to convert the same to an int, because int cannot hold that big a value. 但是,它无法将相同的转换为int,因为int不能保存那么大的值。

Do you really have a practical use case for that old date (1-1-1901) ? 你真的有一个旧日期(1-1-1901)的实际用例吗?

Try rerunning the same with a different date, which gives smaller difference. 尝试使用不同的日期重新运行相同的日期,这会产生较小的差异。 Guess we cannot achieve this using the Seconds.secondsBetween() method. 猜猜我们无法使用Seconds.secondsBetween()方法实现这一点。

Note: The date system of Java/Unix uses 1-1-1970 as starting point. 注意:Java / Unix的日期系统使用1-1-1970作为起点。

getSeconds is defined as returning an int : getSeconds定义为返回int

public int getSeconds()

so, even if you store its result in a long, it can only return a quantity < MAXINT or roughly 64 years. 所以,即使你将结果存储在一个长的,它只能返回一个数量<MAXINT或大约64年。 So in short, if you really need to calculate the number of seconds in century-sized time periods, this method is not for you. 因此,简而言之,如果您确实需要计算世纪大小时间段内的秒数,则此方法不适合您。

As your example measures the distance in seconds between two dates , why not use Hours.getHours() and multiply the result by 3600? 由于您的示例测量两个日期之间的距离(秒),为什么不使用Hours.getHours()并将结果乘以3600? The result should be pretty close to what you want (except for leap seconds I think), and give you a usable range that's big enough for your needs. 结果应该非常接近您想要的(除了我认为的闰秒),并为您提供足够大的可用范围以满足您的需求。

Use the Seconds class 使用Seconds类

DateTime now = DateTime.now();
DateTime dateTime = now.plusMinutes(10);
Seconds seconds = Seconds.secondsBetween(now, dateTime);
System.out.println(seconds.getSeconds());

EDIT: 编辑:

Int type ranges from –2,147,483,648 to 2,147,483,647. Int类型的范围从-2,147,483,648到2,147,483,647。 Your value give you something like 3,565,987,200. 你的价值会给你3,565,987,200之类的东西。 So this method will not work for you 所以这种方法对你不起作用

Workaround: 解决方法:

Date d1 = ...;
Date d2 = ...;
long seconds = (d2.getTime()-d1.getTime())/1000;

Have a look at http://joda-time.sourceforge.net/apidocs/org/joda/time/Seconds.html#secondsBetween(org.joda.time.ReadableInstant , org.joda.time.ReadableInstant) 看看http://joda-time.sourceforge.net/apidocs/org/joda/time/Seconds.html#secondsBetween(org.joda.time.ReadableInstant,org.joda.time.ReadableInstant

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

I think LocalDate()).getSeconds() is wrong, because you want to get the seconds between from two ReadableInstant. 我认为LocalDate())。getSeconds()是错误的,因为你想获得两个ReadableInstant之间的秒数。 Try Seconds.secondsBetween with 2 LocalDates 尝试使用2个LocalDates的Seconds.secondsBetween

Look here: http://www.leveluplunch.com/java/examples/number-of-seconds-between-two-dates/ 请看这里: http//www.leveluplunch.com/java/examples/number-of-seconds-between-two-dates/

  // start day is 1 day in the past
DateTime startDate = new DateTime().minusDays(1);
DateTime endDate = new DateTime();

Seconds seconds = Seconds.secondsBetween(startDate, endDate);

int secondsInDay = seconds.getSeconds();

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM