Java 中两个日期的求和

发布于 2024-08-17 12:56:19 字数 188 浏览 4 评论 0原文

如何在 Java 中添加两个日期?

示例:“2010-01-14 19:16:17”“0000-10-03 01:10:05”的总和
将导致“2010-11-17 20:26:22”。

我知道如何使用日历并逐个字段添加字段来做到这一点。

还有其他方法可以一次将它们全部求和(年/月/日/小时/分钟/秒)吗?

How can I add two dates in Java?

Example: The sum of "2010-01-14 19:16:17" "0000-10-03 01:10:05"
would result in "2010-11-17 20:26:22".

I know how to do it using Calendar and adding field by field.

Is any other way to sum them all (year/month/day/hour/minute/second) at once?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(9

执笏见 2024-08-24 12:56:19

如果您使用的是 Date 对象,您可以这样做:

Date d1 = ...
Date d2 = ...

long sum = d1.getTime() + d2.getTime();

Date sumDate = new Date(sum);

代码使用 .getTime() 方法返回自纪元以来的毫秒数。
不用说 Date 类有很多问题,应该尽可能避免。

您想对其他类型求和吗?

更新:对于 Calendar,我会执行以下操作(基于 javadocs):

Calendar c1 = ...
Calendar c2 = ...
long sum = c1.getTimeInMillis() + c2.getTimeInMillis();
Calendar sumCalendar = (Calendar)c1.clone();
sumCalendar.setTimeInMillis(sum);

更新:正如 Steve 所说,如果您在此处提供的日期假设第​​二个日期是相对于 Java 纪元的,则此操作有效。如果您确实想从“0”年开始,那么您需要考虑到这一点(通过减去您的纪元时间)。

If you are using the Date object, you can just do:

Date d1 = ...
Date d2 = ...

long sum = d1.getTime() + d2.getTime();

Date sumDate = new Date(sum);

The code uses the .getTime() method that returns the number of milliseconds since the epoch.
Needless to say the Date class has a lot of problems and should be avoided when possible.

Do you want to sum other types instead?

Update: for Calendar, I would do the following (based on javadocs):

Calendar c1 = ...
Calendar c2 = ...
long sum = c1.getTimeInMillis() + c2.getTimeInMillis();
Calendar sumCalendar = (Calendar)c1.clone();
sumCalendar.setTimeInMillis(sum);

UPDATED: As Steve stated, this works if the Date you presented here assumes that the second date is with respect to the Java epoch. If you do want to start with year "0", then you need to account for that (by subtracting your epoch time).

孤单情人 2024-08-24 12:56:19

不要将两个日期的时间以毫秒为单位相加!

Date d1 = new Date();
Date d2 = new Date();
Date dTotal = new Date(d1.getTime() + d2.getTime());
System.out.println(dTotal); // Incorrect! Misses about 1970 years.

只需克隆 Calendar 并一一添加日期时间部分即可。

Calendar c1 = Calendar.getInstance();
Calendar c2 = Calendar.getInstance();
Calendar cTotal = (Calendar) c1.clone();
cTotal.add(Calendar.YEAR, c2.get(Calendar.YEAR));
cTotal.add(Calendar.MONTH, c2.get(Calendar.MONTH) + 1); // Months are zero-based!
cTotal.add(Calendar.DATE, c2.get(Calendar.DATE));
cTotal.add(Calendar.HOUR_OF_DAY, c2.get(Calendar.HOUR_OF_DAY));
cTotal.add(Calendar.MINUTE, c2.get(Calendar.MINUTE));
cTotal.add(Calendar.SECOND, c2.get(Calendar.SECOND));
cTotal.add(Calendar.MILLISECOND, c2.get(Calendar.MILLISECOND));
System.out.println(cTotal.getTime()); // Correct!

不用说,JodaTime 在此方面更加智能和干净。

Don't sum the time in millis of the two dates!

Date d1 = new Date();
Date d2 = new Date();
Date dTotal = new Date(d1.getTime() + d2.getTime());
System.out.println(dTotal); // Incorrect! Misses about 1970 years.

Just clone the Calendar and add the datetime parts one by one.

Calendar c1 = Calendar.getInstance();
Calendar c2 = Calendar.getInstance();
Calendar cTotal = (Calendar) c1.clone();
cTotal.add(Calendar.YEAR, c2.get(Calendar.YEAR));
cTotal.add(Calendar.MONTH, c2.get(Calendar.MONTH) + 1); // Months are zero-based!
cTotal.add(Calendar.DATE, c2.get(Calendar.DATE));
cTotal.add(Calendar.HOUR_OF_DAY, c2.get(Calendar.HOUR_OF_DAY));
cTotal.add(Calendar.MINUTE, c2.get(Calendar.MINUTE));
cTotal.add(Calendar.SECOND, c2.get(Calendar.SECOND));
cTotal.add(Calendar.MILLISECOND, c2.get(Calendar.MILLISECOND));
System.out.println(cTotal.getTime()); // Correct!

Needless to say, JodaTime is smarter and cleaner with this.

三生一梦 2024-08-24 12:56:19

一如既往,我会推荐 Java 8 日期/时间 API 或 Joda 进行日期/时间工作,因为它们更加更加强大和直观。

您可以将持续时间和周期添加到 DateTime 简单地反对。您可以同样轻松地添加分钟/秒/月。

但是,您不能直接添加两个日期,因为这实际上没有意义。这有力地说明了为什么 Joda 可以提供帮助——它可以阻止你做你不应该做的事情。

As always, I would recommend the Java 8 date/time APIs or Joda for date/time work, since they are much more powerful and intuitive.

You can add durations and periods to a DateTime object trivially. You can add minutes/seconds/months equally easily.

However, you can't add two dates directly, since that doesn't really make sense. This is a powerful illustration of why Joda is a help - it stops you doing stuff that you really shouldn't be doing.

ら栖息 2024-08-24 12:56:19

tl;dr

LocalDateTime later = 
    LocalDateTime
    .parse ( 
        "2010-01-14 19:16:17"
        .replace ( " " , "T" ) 
    )
    .plus( Period.parse ( "P10M3D" ) )
    .plus( Duration.parse ( "PT1H10M5S" ) ) 
;

ISO 8601

使用与时刻相同的格式来表示时间跨度会造成混乱。跨度与时刻完全不同。

我建议使用标准的 ISO 8601 格式 PnYnMnDTnHnMnS。在此格式中,P 标记开始(可能是“Period”),T 将年-月-日部分与时-分-秒部分分开。

示例值:

  • PT1H30M → 一个半小时。
  • P3Y6M4DT12H30M5S → 三年六个月零四天十二小时三十分钟零五秒。
  • P10M3DT1H10M5S → 您的问题的持续时间为0000-10-03 01:10:05

java.time

问题和其他答案使用麻烦的旧日期时间类,现在已经过时了 java.time 框架内置于 Java 8 及更高版本中。请参阅 Oracle 教程。许多 java.time 功能已向后移植到 Java 6 和 Java 6。 ThreeTen-Backport 中的 7 并在 ThreeTenABP

在解析和生成表示日期时间值的字符串时,java.time 类默认使用 ISO 8601 格式。

该问题没有提供任何时区信息,因此这里我们使用 LocalDateTime 类。如果我们知道相对于 UTC 的偏移量,我们将使用 OffsetDateTime 类,如果我们知道时区,我们将使用 ZonedDateTime 类。

java.time 中的时间跨度被划分为一对类。年-月-日由 表示period 类和小时-分钟-秒由 持续时间 类。

结合这些时间,我们确实可以执行日期时间数学运算。在这里,我们将一段时间添加到开始日期时间以获得结果日期时间。我们只需很少的代码行即可完成此操作。结果确实是提问者所期望的。

我们通过用 T 替换中间的空格,将输入字符串转换为规范的 ISO 8601 格式。

LocalDateTime ldt = LocalDateTime.parse ( "2010-01-14 19:16:17".replace ( " " , "T" ) );
//"0000-10-03 01:10:05"
Period period = Period.parse ( "P10M3D" );
Duration duration = Duration.parse ( "PT1H10M5S" );
LocalDateTime result = ldt.plus ( period ).plus ( duration );

与问题中预期的结果进行比较。

LocalDateTime expectation = LocalDateTime.parse ( "2010-11-17 20:26:22".replace ( " " , "T" ) );
Boolean isSame = result.equals ( expectation );

转储到控制台。

System.out.println ( "ldt: " + ldt + " + period: " + period + " + duration: " + duration + " is result: " + result + " compared to expectation: " + expectation + " is the same: " + isSame );

ldt: 2010-01-14T19:16:17 + 周期: P10M3D + 持续时间: PT1H10M5S 结果: 2010-11-17T20:26:22 与预期相比: 2010-11-17T20:26:22 是相同的:正确

tl;dr

LocalDateTime later = 
    LocalDateTime
    .parse ( 
        "2010-01-14 19:16:17"
        .replace ( " " , "T" ) 
    )
    .plus( Period.parse ( "P10M3D" ) )
    .plus( Duration.parse ( "PT1H10M5S" ) ) 
;

ISO 8601

The representation of a span-of-time using the same format as a moment is creating confusion. A span is not at all the same as a moment.

Instead of using YYYY-MM-DD HH-MM-SS format for a span of time, I suggest using the standard ISO 8601 format of PnYnMnDTnHnMnS. In this format, the P marks the beginning (for "Period" presumably) and the T separates the years-month-days portion from the hours-minutes-seconds portion.

Example values:

  • PT1H30M → One and a half hours.
  • P3Y6M4DT12H30M5S → Three years, six months, four days, twelve hours, thirty minutes, and five seconds.
  • P10M3DT1H10M5S → Your Question’s duration of 0000-10-03 01:10:05.

java.time

The Question and the other Answers use troublesome old date-time classes now outmoded by the java.time framework built into Java 8 and later. See Oracle Tutorial. Much of the java.time functionality has been back-ported to Java 6 & 7 in ThreeTen-Backport and further adapted to Android in ThreeTenABP.

The java.time classes use ISO 8601 formats by default when parsing and generating Strings that represent date-time values.

The Question does not provide any time zone info, so here we use the LocalDateTime class. If we know an offset-from-UTC we would use the OffsetDateTime class, and if even better we knew a time zone, we would use the ZonedDateTime class.

Spans of time in java.time are divided amongst a pair of classes. Years-months-days are represented by the Period class, and hours-minutes-seconds are handled by the Duration class.

Combining these times, we can indeed perform date-time math. Here we add a span of time to an starting date-time to get a resulting date-time. And we do so in very few lines of code. The result is indeed that expected by the Question.

We convert the input strings to canonical ISO 8601 format by replacing the SPACE in the middle with a T.

LocalDateTime ldt = LocalDateTime.parse ( "2010-01-14 19:16:17".replace ( " " , "T" ) );
//"0000-10-03 01:10:05"
Period period = Period.parse ( "P10M3D" );
Duration duration = Duration.parse ( "PT1H10M5S" );
LocalDateTime result = ldt.plus ( period ).plus ( duration );

Compare to the result expected in the Question.

LocalDateTime expectation = LocalDateTime.parse ( "2010-11-17 20:26:22".replace ( " " , "T" ) );
Boolean isSame = result.equals ( expectation );

Dump to console.

System.out.println ( "ldt: " + ldt + " + period: " + period + " + duration: " + duration + " is result: " + result + " compared to expectation: " + expectation + " is the same: " + isSame );

ldt: 2010-01-14T19:16:17 + period: P10M3D + duration: PT1H10M5S is result: 2010-11-17T20:26:22 compared to expectation: 2010-11-17T20:26:22 is the same: true

卸妝后依然美 2024-08-24 12:56:19

您希望对这两个日历执行 getTimeInMillis() 操作,这样您就可以将两个诚实的 long 值相加。然后,您可以使用该日历的 setTimeInMillis() 方法获取总和并将其存储在新日历中。

当然,是否要添加如上所示的两个 Calendar 或如 notnoop 的答案中所示的两个 Date 取决于您。效果类似,只是取决于你想对结果做什么。 Date 主要用于存储和/或转换为字符串以供打印或显示,而 Calendar 则可以让您随意调整各个时间值(如果您愿意的话)选择。

正如其他人提到的,您在使用 DateCalendar 时犯了一些概念上的禁忌,它们旨在存储“真实”日期和时间,例如20世纪或21世纪,作为间隔,即时间跨度。标准 Java 库中的类没有为您提供真正有用的工具来处理此问题,这就是开发 Joda 类的原因。所有日期/时间处理中的酷孩子都使用它们;但另一方面,这涉及下载和管理第三方库。

You want to do getTimeInMillis() on both those Calendars so you'll have two honest-to-goodness long values you can add up. You can then take the sum and stash it in a new Calendar using that Calendar's setTimeInMillis() method.

Whether you want to add two Calendars as shown above or two Dates as shown in notnoop's answer is up to you, of course. The effect is similar, it just depends on what you want to do with the result. A Date is mostly just good for storing and/or converting to a String for printing out or displaying, whereas a Calendar will let you fiddle with the individual time values should you so choose.

As others have mentioned, you're committing some conceptual no-no's in using a Date or Calendar, which are meant to store "real" dates and times, e.g. ones in the 20th or 21st century, as intervals, i.e. time spans. The classes in the standard Java library don't give you really useful tools to handle this, which is why the Joda classes were developed. All the cool kids in date/time processing use those; but on the other hand that involves downloading and managing a 3rd party library.

他不在意 2024-08-24 12:56:19

notnoop 的答案绝对是正确的。但是,如果您要对日期、时间和间隔进行大量处理,我建议您查看 apache commons langjoda-time 库。

JDK7 将为 joda-time 提供的一些功能提供更好的支持。只是说......如果您的应用程序大量使用这些东西,这可能是一个考虑因素。

notnoop answer is definitely correct. However, if you are going to do lots of processing of dates, times and intervals, I suggest that you look at class DateUtils in apache commons lang and at joda-time library.

JDK7 will come with better support for some of the features that joda-time provides. Just saying ... it might be a consideration if your app makes heavy usage of this stuff.

萤火眠眠 2024-08-24 12:56:19

您需要定义您的 EPOCH。 Java 纪元(与 Unix 一样)是 1970 年 1 月 1 日 GMT/UTC。我假设您认为您从 0000 年 1 月 1 日起添加了 10 个月、3 天和一些奇怪的时间,但您的纪元偏移量一直到 1970 年。数学可能不一定有效。

使用 Calendar 或 Joda(如上所述)。如果您只是想添加秒数和天数 (&c),那么请随意将所述毫秒数添加到您的第一个日期对象中。

You need to define your EPOCH. The Java epoch (like Unix) is 1 Jan 1970 GMT/UTC. I assume you think you're adding ten months, 3 days and some odd hours from 1 Jan 0000 but you have a epoch offset until 1970. The maths may not necessarily work.

Use Calendar or Joda (as mentioned). If you just simply want to add a number of seconds and days (&c) then feel free to add said # of milliseconds to your first date object.

感悟人生的甜 2024-08-24 12:56:19

在java中使用日历类add方法添加两个日期。

Calendar calendar=Calendar.getInstance();

calendar.add(Calendar.Date,23);

calendar.add(Calendar.Month,13);

calendar.add(Calendar.Year,15);

通过使用 Calendar 类中的 add 方法,我们可以向现有日期添加日、月、年。

单击此处查看完整程序。

Use calendar class add method to add two dates in java.

Calendar calendar=Calendar.getInstance();

calendar.add(Calendar.Date,23);

calendar.add(Calendar.Month,13);

calendar.add(Calendar.Year,15);

By using add method in Calendar class we can add day,month,year to the existing date.

click here for complete program.

养猫人 2024-08-24 12:56:19

我偶尔也会犯这种做法,将时间间隔存储在日期对象中并按照 notnoop 的建议使用 getTime() 。

有用。与某些观点相反,它确实有效。我只是忽略了该间隔可能代表意外的日期。对我来说,向日期添加间隔(例如 [6 年、6 个月、6 天、6 小时、6 分钟、6 秒])是一种快速而肮脏的方法。

I am occasionally guilty of this practice too, storing time interval in a date object and using getTime() as suggested by notnoop.

It works. Contrary to certain opinion, it certainly works. I just ignore that the interval could be representative of an unintended date. It is a quick and dirty way for me to add an interval, say, [6 years, 6 months, 6 days, 6 hours, 6 minutes, 6 seconds] to a date.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文