View Javadoc
1   /*
2    * Copyright (C) 2020-2023 Dipl.-Inform. Kai Hofmann. All rights reserved!
3    */
4   package de.powerstat.validation.values;
5   
6   
7   import java.util.Objects;
8   
9   import de.powerstat.validation.interfaces.IValueObject;
10  
11  
12  /**
13   * Month.
14   *
15   * Not DSGVO relevant.
16   *
17   * TODO constructor with year
18   * TODO daysWithin() = 31, 30, 29, 28, n (Year specific for february, or october 1582)
19   * TODO Listener
20   * TODO Translations short/long
21   */
22  public final class Month implements Comparable<Month>, IValueObject
23   {
24    /* *
25     * Cache for singletons.
26     */
27    // private static final Map<Integer, Month> CACHE = new WeakHashMap<>();
28  
29    /**
30     * Overflow constant.
31     */
32    private static final String OVERFLOW = "Overflow"; //$NON-NLS-1$
33  
34    /**
35     * Underflow constant.
36     */
37    private static final String UNDERFLOW = "Underflow"; //$NON-NLS-1$
38  
39    /**
40     * Month.
41     */
42    private final int month;
43  
44  
45    /**
46     * Constructor.
47     *
48     * @param month Month 1-12
49     * @throws IndexOutOfBoundsException When the month is less than 1 or greater than 12
50     */
51    private Month(final int month)
52     {
53      super();
54      if ((month < 1) || (month > 12))
55       {
56        throw new IndexOutOfBoundsException("Month number out of range (1-12)!"); //$NON-NLS-1$
57       }
58      this.month = month;
59     }
60  
61  
62    /**
63     * Month factory.
64     *
65     * @param month Month 1-12
66     * @return Month object
67     * @throws IndexOutOfBoundsException When the month is less than 1 or greater than 12
68     */
69    public static Month of(final int month)
70     {
71      /*
72      synchronized (Month.class)
73       {
74        Month obj = Month.CACHE.get(month);
75        if (obj != null)
76         {
77          return obj;
78         }
79        obj = new Month(month);
80        Month.CACHE.put(Integer.valueOf(month), obj);
81        return obj;
82       }
83      */
84      return new Month(month);
85     }
86  
87  
88    /**
89     * Month factory.
90     *
91     * @param value Month 1-12 string
92     * @return Month object
93     * @throws IndexOutOfBoundsException When the month is less than 1 or greater than 12
94     */
95    public static Month of(final String value)
96     {
97      return of(Integer.parseInt(value));
98     }
99  
100 
101   /**
102    * Returns the value of this Month as an int.
103    *
104    * @return The numeric value represented by this object after conversion to type int.
105    */
106   public int intValue()
107    {
108     return this.month;
109    }
110 
111 
112   /**
113    * Returns the value of this Month as an String.
114    *
115    * @return The numeric value represented by this object after conversion to type String.
116    */
117   @Override
118   public String stringValue()
119    {
120     return String.valueOf(this.month);
121    }
122 
123 
124   /**
125    * Calculate hash code.
126    *
127    * @return Hash
128    * @see java.lang.Object#hashCode()
129    */
130   @Override
131   public int hashCode()
132    {
133     return Integer.hashCode(this.month);
134    }
135 
136 
137   /**
138    * Is equal with another object.
139    *
140    * @param obj Object
141    * @return true when equal, false otherwise
142    * @see java.lang.Object#equals(java.lang.Object)
143    */
144   @Override
145   public boolean equals(final Object obj)
146    {
147     if (this == obj)
148      {
149       return true;
150      }
151     if (!(obj instanceof Month))
152      {
153       return false;
154      }
155     final Month other = (Month)obj;
156     return this.month == other.month;
157    }
158 
159 
160   /**
161    * Returns the string representation of this Month.
162    *
163    * The exact details of this representation are unspecified and subject to change, but the following may be regarded as typical:
164    *
165    * "Month[month=1]"
166    *
167    * @return String representation of this Month
168    * @see java.lang.Object#toString()
169    */
170   @Override
171   public String toString()
172    {
173     final var builder = new StringBuilder();
174     builder.append("Month[month=").append(this.month).append(']'); //$NON-NLS-1$
175     return builder.toString();
176    }
177 
178 
179   /**
180    * Compare with another object.
181    *
182    * @param obj Object to compare with
183    * @return 0: equal; 1: greater; -1: smaller
184    * @see java.lang.Comparable#compareTo(java.lang.Object)
185    */
186   @Override
187   public int compareTo(final Month obj)
188    {
189     Objects.requireNonNull(obj, "obj"); //$NON-NLS-1$
190     return Integer.compare(this.month, obj.month);
191    }
192 
193 
194   /**
195    * Add months to this month.
196    *
197    * @param months Months to add to this month
198    * @return New month after adding the months to this month
199    * @throws ArithmeticException In case of an overflow
200    */
201   public Month add(final Months months)
202    {
203     final long newMonth = Math.toIntExact(Math.addExact(this.month, months.longValue()));
204     if (newMonth > 12) // while (newMonth > 12)
205      {
206       // TODO Listener
207       // newMonth -= 12;
208       // incrementYear();
209       throw new ArithmeticException(Month.OVERFLOW);
210      }
211     return Month.of(Math.toIntExact(newMonth));
212    }
213 
214 
215   /**
216    * Subtract months from this month.
217    *
218    * @param months Months to subtract from this month
219    * @return New month after subtracting months from this month
220    * @throws ArithmeticException In case of an underflow
221    */
222   public Month subtract(final Months months)
223    {
224     final long newMonth = Math.toIntExact(Math.subtractExact(this.month, months.longValue()));
225     if (newMonth <= 0) // while (newMonth <= 0)
226      {
227       // TODO Listener
228       // newMonth += 12;
229       // decrementYear();
230       throw new ArithmeticException(Month.UNDERFLOW);
231      }
232     return Month.of(Math.toIntExact(newMonth));
233    }
234 
235 
236   /**
237    * Increment this month.
238    *
239    * @return New month after incrementing this month
240    * @throws ArithmeticException In case of an overflow
241    */
242   public Month increment()
243    {
244     final int newMonth = Math.incrementExact(this.month);
245     if (newMonth == 13)
246      {
247       // TODO Listener
248       // newMonth = 1;
249       // incrementYear();
250       throw new ArithmeticException(Month.OVERFLOW);
251      }
252     return Month.of(newMonth);
253    }
254 
255 
256   /**
257    * Decrement this month.
258    *
259    * @return New month after decrement this month
260    * @throws ArithmeticException In case of an overflow
261    */
262   public Month decrement()
263    {
264     final int newMonth = Math.decrementExact(this.month);
265     if (newMonth == 0)
266      {
267       // TODO Listener
268       // newMonth = 12;
269       // decrementYear();
270       throw new ArithmeticException(Month.UNDERFLOW);
271      }
272     return Month.of(newMonth);
273    }
274 
275  }