如何使用 Joda 时间库计算下一个生日

How to calculate next birthday using Joda time libaray

我有两个日期,格式如下 出生日期假设为 1995/04/09 和当前日期 2016/07/24 那么我怎样才能得到下一个生日剩余的月数和天数

public String getNextBirthdayMonths() {
     LocalDate dateOfBirth = new LocalDate(startYear, startMonth, startDay);
     LocalDate currentDate = new LocalDate();

     Period period = new Period(dateOfBirth, currentDate);
     PeriodFormatter periodFormatter = new PeriodFormatterBuilder()
                              .appendMonths().appendSuffix(" Months ")
                              .appendDays().appendSuffix(" Days ")
                              .printZeroNever().toFormatter();

        String nextBirthday = periodFormatter.print(period);
        return "" + nextBirthday;
}

请任何人帮助我在此先感谢

根据您的问题,您想使用 Joda 计算下一个生日。 下面的代码将帮助您给出即将到来的生日月份。

   LocalDate dateOfBirth = new LocalDate(1995, 4, 9);
   LocalDate currentDate = new LocalDate();
   // Take birthDay  and birthMonth  from dateOfBirth 
   int birthDay = dateOfBirth.getDayOfMonth();
   int birthMonth = dateOfBirth.getMonthOfYear();
   // Current year's birthday
   LocalDate currentYearBirthDay = new LocalDate().withDayOfMonth(birthDay)
                        .withMonthOfYear(birthMonth);
   PeriodType monthDay = PeriodType.yearMonthDayTime().withYearsRemoved();
   PeriodFormatter periodFormatter = new PeriodFormatterBuilder()
        .appendMonths().appendSuffix(" Months ").appendDays()
        .appendSuffix(" Days ").printZeroNever().toFormatter();
   if (currentYearBirthDay.isAfter(currentDate)) {
       Period period = new Period(currentDate, currentYearBirthDay,monthDay );
       String currentBirthday = periodFormatter.print(period);
       System.out.println(currentBirthday );
   } else {
        LocalDate nextYearBirthDay =currentYearBirthDay.plusYears(1);
        Period period = new Period(currentDate, nextYearBirthDay ,monthDay );
        String nextBirthday = periodFormatter.print(period);
        System.out.println(nextBirthday);
   }

输出:

8 Months 16 Days

我会找到下一个生日日期

LocalDate today = new LocalDate();
LocalDate birthDate = new LocalDate(1900, 7, 12);

int age = new Period(birthDate, today).getYears();

LocalDate nextBirthday = birthDate.plusYears(age + 1);

然后计算距离该日期还剩多少月和天

PeriodType monthsAndDays = PeriodType.yearMonthDay().withYearsRemoved();
Period leftToBirthday = new Period(today, nextBirthday, monthsAndDays);

PeriodFormatter periodFormatter = new PeriodFormatterBuilder()
        .appendMonths().appendSuffix(" Months ")
        .appendDays().appendSuffix(" Days ")
        .toFormatter();

return periodFormatter.print(leftToBirthday);

java.time

Joda-Time 团队建议迁移到 java.time classes。

正在解析

您输入的值接近标准 ISO 8601 格式。我们可以通过用连字符替换斜杠来转换它。

String input = "1995/04/09".replace ( "/" , "-" );

java.time classes 默认使用 ISO 8601 格式来解析和生成表示日期时间值的字符串。因此无需定义格式化模式。 LocalDate class 可以直接解析输入。

LocalDate

LocalDate class 表示没有时间和时区的仅日期值。

LocalDate dateOfBirth = LocalDate.parse ( input );

MonthDay

我们只需要月份和日期就可以确定生日等重复发生的年度事件。为此,java.time classes 包括 MonthDay

MonthDay monthDayOfBirth = MonthDay.from ( dateOfBirth );

接下来我们需要当前日期。请注意,虽然 LocalDate 不会 存储 内部时区,但我们需要一个时区来确定今天的日期。对于任何给定时刻,世界各地的日期因时区而异。例如,午夜后几分钟在巴黎是新的一天,而在蒙特利尔仍然是“昨天”。

ZoneId zoneId = ZoneId.of ( "America/Montreal" );
LocalDate today = LocalDate.now ( zoneId );
int year = today.getYear ();

有了当前年份,我们可以通过询问 MonthDay 实例来创建那一年的生日。

LocalDate nextBirthday = monthDayOfBirth.atYear ( year );

验证确定的日期确实是下一个生日。可能已经过去了,在这种情况下我们需要增加一年。

if ( nextBirthday.isBefore ( today ) ) {
    nextBirthday = nextBirthday.plusYears ( 1 );
}

转储到控制台。

System.out.println ( "input: " + input + " | dateOfBirth: " + dateOfBirth + " | today: " + today + " | nextBirthday: " + nextBirthday );

input: 1995-04-09 | dateOfBirth: 1995-04-09 | today: 2016-07-24 | nextBirthday: 2017-04-09

Period

现在我们继续计算到下一个生日还有多少时间。 Period class 表示以年、月、日表示的时间跨度。

 Period period = Period.between ( today ,  nextBirthday ).normalized ();

我们可以查询月份部分和日期部分。

int months = period.getMonths();
int days = period.getDays();

字符串

至于在字符串中报告这些值,用于数据交换以及可能用于向人类报告的一些内容,我建议使用标准 ISO 8601 格式来处理与时间轴无关的时间跨度:PnYnMnDTnHnMnSP 标记开始,T 分隔小时-分钟-秒部分(如果有)。所以一个月零六天就是 P1M6D.

PeriodDuration java.time 中的 classes 在其 toString 方法中默认使用此格式。

String output = period.toString();

或创建您自己的字符串。

String message = months + " Months " + days + " Days";
System.out.println ( "period: " + period.toString () + " | message: " + message );

period: P8M16D | message: 8 Months 16 Days

我希望我知道一种使用 DateTimeFormatter 自动本地化为 Locale 指定的人类语言和文化规范的方法,就像我们可以使用其他 java.time 类型一样。但不幸的是,这对于 PeriodDuration 对象似乎是不可能的。

TemporalAdjuster

可以将此代码打包到 class 实现 TemporalAdjuster 中。然后你可以用简单的 with 语法来使用它。

LocalDate nextBirthday = dateOfBirth.with( MyTemporalAdjusters.nextRecurringMonthDay( myYearMonth ) );

关于java.time

java.time framework is built into Java 8 and later. These classes supplant the troublesome old legacy date-time classes such as java.util.Date, Calendar, & SimpleDateFormat.

Joda-Time project, now in maintenance mode, advises migration to the java.time classes.

要了解更多信息,请参阅 Oracle Tutorial. And search Stack Overflow for many examples and explanations. Specification is JSR 310

从哪里获得java.time classes?

  • Java SE 8 and SE 9 及更高版本
    • 内置。
    • 标准 Java API 的一部分,带有捆绑实施。
    • Java 9 添加了一些小功能和修复。
  • Java SE 6 and SE 7
  • Android
    • ThreeTenABP 项目专门为 Android 改编 ThreeTen-Backport(如上所述)。
    • 参见

ThreeTen-Extra project extends java.time with additional classes. This project is a proving ground for possible future additions to java.time. You may find some useful classes here such as Interval, YearWeek, YearQuarter, and more.