Как рассчитать следующий день рождения, используя 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;
}

Пожалуйста, кто-нибудь, помогите мне Спасибо заранее

3 ответа

Решение

java.time

Команда Joda-Time советует перейти на классы java.time.

анализ

Ваше входное значение близко к стандартному формату ISO 8601. Мы можем преобразовать его, заменив косую черту дефисами.

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

Классы java.time по умолчанию используют форматы ISO 8601 для анализа и генерации строк, представляющих значения даты и времени. Поэтому нет необходимости определять шаблон форматирования. LocalDate Класс может напрямую анализировать ввод.

LocalDate

LocalDate класс представляет значение только для даты без времени суток и без часового пояса.

LocalDate dateOfBirth = LocalDate.parse ( input );

MonthDay

Все, что нам нужно для повторяющихся ежегодных мероприятий, таких как день рождения, - это месяц и день. Классы java.time включают 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 );

вход: 1995-04-09 | дата рождения: 1995-04-09 | сегодня: 2016-07-24 | следующий день рождения: 2017-04-09

Period

Теперь мы переходим к подсчету времени до следующего дня рождения. Period класс представляет промежуток времени в терминах лет, месяцев и дней.

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

Мы можем опросить часть месяцев и часть дней.

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

Струны

Что касается сообщения этих значений в строке, для обмена данными и, возможно, для некоторых отчетов людям, я предлагаю использовать стандартный формат ISO 8601 для промежутка времени, не привязанного к временной шкале: PnYnMnDTnHnMnS, P отмечает начало и T отделяет часть часов-минут-секунд (если есть). Таким образом, один месяц и шесть дней будут P1M6D,

Period а также Duration классы в java.time используют этот формат по умолчанию в своих toString методы.

String output = period.toString();

Или создайте свою собственную строку.

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

период: P8M16D | сообщение: 8 месяцев 16 дней

Я хотел бы знать, как использовать DateTimeFormatter автоматически локализовать на человеческий язык и культурные нормы, определенные Locale как мы можем с другими типами java.time. Но это не представляется возможным с Period а также Duration объекты, к сожалению.

TemporalAdjuster

Может быть возможно упаковать этот код в класс, реализующий TemporalAdjuster, Тогда вы можете использовать его с простым with синтаксис.

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

О java.time

Инфраструктура java.time встроена в Java 8 и более поздние версии. Эти классы вытесняют проблемные старые классы даты и времени, такие как java.util.Date, Calendar & SimpleDateFormat,

Проект Joda-Time, находящийся сейчас в режиме обслуживания, рекомендует перейти на классы java.time.

Чтобы узнать больше, смотрите Oracle Tutorial. И поиск переполнения стека для многих примеров и объяснений. Спецификация JSR 310.

Где взять классы java.time?

  • Java SE 8 и SE 9 и позже
    • Встроенный.
    • Часть стандартного Java API со встроенной реализацией.
    • Java 9 добавляет некоторые незначительные функции и исправления.
  • Java SE 6 и SE 7
    • Большая часть функциональности java.time перенесена на Java 6 и 7 в ThreeTen-Backport.
  • Android

Проект ThreeTen-Extra расширяет java.time дополнительными классами. Этот проект является полигоном для возможных будущих дополнений к java.time. Вы можете найти некоторые полезные классы здесь, такие как Interval, YearWeek, YearQuarterи многое другое.

По вашему вопросу, Вы хотите рассчитать следующий день рождения, используя Йоду. Приведенный ниже код поможет вам определить ближайшие дни рождения.

   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 месяцев 16 дней

Я бы нашел следующую дату рождения

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);
Другие вопросы по тегам