Чистый код. Создание, анализ и рефакторинг — страница 89 из 94

   2  * JCommon : библиотека классов общего назначения для платформы Java(tm)

   3  * ========================================================================

   4  *

   5  * (C) Copyright 2000–2005, by Object Refinery Limited and Contributors.

   ...

  36  */

  37 package org.jfree.date;

  38

  39 import java.io.Serializable;

  40 import java.util.*;

  41

  42 /**

  43  * Абстрактный класс, представляющий неизменяемые даты с точностью

  44  * до одного дня. Реализация отображает дату на целое число, представляющее

  45  * смещение в днях от фиксированной точки отсчета.

  46  *

  47  *  Почему не использовать java.util.Date? Будем использовать, где это имеет смысл.

  48  *  Класс java.util.Date бывает *слишком* точным - он представляет момент

  49  *  времени с точностью до 1/100 секунды (при этом сама дата зависит от часового

  50  *  пояса). Иногда бывает нужно просто представить конкретный день (скажем,

  51  *  21 января 2015), не заботясь о времени суток, часовом поясе и т.д.

  52  *  Именно для таких ситуаций определяется класс DayDate.

  53  *

  54  * Для создания экземпляра используется DayDateFactory.makeDate.

  55  *

  56  * @author Дэвид Гилберт

  57  * @author Роберт С. Мартин провел значительную переработку.

  58  */

  59

  60 public abstract class DayDate implements Comparable, Serializable {

  61   public abstract int getOrdinalDay();

  62   public abstract int getYear();

  63   public abstract Month getMonth();

  64   public abstract int getDayOfMonth();

  65

  66   protected abstract Day getDayOfWeekForOrdinalZero();

  67

  68   public DayDate plusDays(int days) {

  69     return DayDateFactory.makeDate(getOrdinalDay() + days);

  70   }

  71

  72   public DayDate plusMonths(int months) {

  73     int thisMonthAsOrdinal = getMonth().toInt() - Month.JANUARY.toInt();

  74     int thisMonthAndYearAsOrdinal = 12 * getYear() + thisMonthAsOrdinal;

  75     int resultMonthAndYearAsOrdinal = thisMonthAndYearAsOrdinal + months;

  76     int resultYear = resultMonthAndYearAsOrdinal / 12;

  77     int resultMonthAsOrdinal = resultMonthAndYearAsOrdinal % 12 + Month.JANUARY.

         toInt();

  78     Month resultMonth = Month.fromInt(resultMonthAsOrdinal);

  79     int resultDay = correctLastDayOfMonth(getDayOfMonth(), resultMonth, resultYear);

  80     return DayDateFactory.makeDate(resultDay, resultMonth, resultYear);

  81   }

  82

  83   public DayDate plusYears(int years) {

  84     int resultYear = getYear() + years;

  85     int resultDay = correctLastDayOfMonth(getDayOfMonth(), getMonth(), resultYear);

  86     return DayDateFactory.makeDate(resultDay, getMonth(), resultYear);

  87   }

  88

  89   private int correctLastDayOfMonth(int day, Month month, int year) {

  90     int lastDayOfMonth = DateUtil.lastDayOfMonth(month, year);

  91     if (day > lastDayOfMonth)

  92         day = lastDayOfMonth;

  93     return day;

  94   }

  95

  96   public DayDate getPreviousDayOfWeek(Day targetDayOfWeek) {

  97     int offsetToTarget = targetDayOfWeek.toInt() - getDayOfWeek().toInt();

  98     if (offsetToTarget >= 0)

  99       offsetToTarget -= 7;

100     return plusDays(offsetToTarget);

101   }

102

103   public DayDate getFollowingDayOfWeek(Day targetDayOfWeek) {

104     int offsetToTarget = targetDayOfWeek.toInt() - getDayOfWeek().toInt();

105     if (offsetToTarget <= 0)

106       offsetToTarget += 7;

107     return plusDays(offsetToTarget);

108   }

109

110   public DayDate getNearestDayOfWeek(Day targetDayOfWeek) {

111     int offsetToThisWeeksTarget = targetDayOfWeek.toInt() - getDayOfWeek().

         toInt();

112     int offsetToFutureTarget = (offsetToThisWeeksTarget + 7) % 7;

113     int offsetToPreviousTarget = offsetToFutureTarget - 7;

114


Листинг Б.7 (продолжение)

115     if (offsetToFutureTarget > 3)

116       return plusDays(offsetToPreviousTarget);

117     else

118       return plusDays(offsetToFutureTarget);

119   }

120

121   public DayDate getEndOfMonth() {

122     Month month = getMonth();

123     int year = getYear();

124     int lastDay = DateUtil.lastDayOfMonth(month, year);

125     return DayDateFactory.makeDate(lastDay, month, year);

126   }

127

128   public Date toDate() {

129     final Calendar calendar = Calendar.getInstance();

130     int ordinalMonth = getMonth().toInt() - Month.JANUARY.toInt();

131     calendar.set(getYear(), ordinalMonth, getDayOfMonth(), 0, 0, 0);

132     return calendar.getTime();

133   }

134

135   public String toString() {

136     return String.format(«%02d-%s-%d», getDayOfMonth(), getMonth(), getYear());

137   }

138

139   public Day getDayOfWeek() {

140     Day startingDay = getDayOfWeekForOrdinalZero();

141     int startingOffset = startingDay.toInt() - Day.SUNDAY.toInt();

142     int ordinalOfDayOfWeek = (getOrdinalDay() + startingOffset) % 7;

143     return Day.fromInt(ordinalOfDayOfWeek + Day.SUNDAY.toInt());

144   }

145

146   public int daysSince(DayDate date) {

147     return getOrdinalDay() - date.getOrdinalDay();