View Javadoc
1   package net.sumaris.core.util;
2   
3   /*-
4    * #%L
5    * Quadrige3 Core :: Quadrige3 Core Shared
6    * $Id:$
7    * $HeadURL:$
8    * %%
9    * Copyright (C) 2017 Ifremer
10   * %%
11   * This program is free software: you can redistribute it and/or modify
12   * it under the terms of the GNU General Public License as
13   * published by the Free Software Foundation, either version 3 of the
14   * License, or (at your option) any later version.
15   * 
16   * This program is distributed in the hope that it will be useful,
17   * but WITHOUT ANY WARRANTY; without even the implied warranty of
18   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19   * GNU General Public License for more details.
20   * 
21   * You should have received a copy of the GNU General Public
22   * License along with this program.  If not, see
23   * <http://www.gnu.org/licenses/gpl-3.0.html>.
24   * #L%
25   */
26  
27  import com.google.common.base.Preconditions;
28  import org.apache.commons.lang3.StringUtils;
29  import org.nuiton.util.DateUtil;
30  
31  import java.sql.Timestamp;
32  import java.text.ParseException;
33  import java.text.SimpleDateFormat;
34  import java.util.Calendar;
35  import java.util.Date;
36  import java.util.TimeZone;
37  
38  /**
39   * <p>Dates class.</p>
40   */
41  public class Dates extends org.apache.commons.lang3.time.DateUtils{
42  	
43      /**
44       * Remove a amount of month to a date
45       *
46       * @param date a {@link Date} object.
47       * @param amount the amount to remove, in month
48       * @return a new date (= the given date - amount in month)
49       */
50      public static Date removeMonth(Date date, int amount) {
51      	Preconditions.checkNotNull(date);
52      	Preconditions.checkArgument(amount > 0);
53  
54      	// Compute the start date
55          Calendar calendar = Calendar.getInstance();
56  		calendar.setTimeInMillis(date.getTime());
57  		calendar.set(Calendar.HOUR_OF_DAY, 0);
58  		calendar.set(Calendar.DAY_OF_MONTH, 1);
59  		calendar.set(Calendar.MONTH, calendar.get(Calendar.MONTH)-amount);
60  		return calendar.getTime();
61      }
62  
63      /**
64       * Get the number of days between two dates
65       *
66       * @param startDate a {@link Date} object.
67       * @param endDate a {@link Date} object.
68       * @return a number of hours
69       */
70      public static double hoursBetween(Date startDate, Date endDate){
71      	double millis = endDate.getTime() - startDate.getTime();
72          return millis / (1000 * 60 * 60);
73      }
74  
75      /**
76       * Add to date some hours
77       *
78       * @param date a {@link Date} object.
79       * @param amount a {@link Double} object.
80       * @return a date (= date + amount)
81       */
82      public static Date addHours(Date date, Double amount){
83      	long millis = (long) (date.getTime() + amount * (1000 * 60 * 60));
84          return new Date(millis);
85      }
86  
87  
88      /**
89       * Get the last second time of a day: 23:59:59 (0 millisecond)
90       *
91       * @param date a {@link Date} object.
92       * @return a {@link Date} object.
93       */
94      public static Date lastSecondOfTheDay(Date date) {
95          Calendar calendar = Calendar.getInstance();
96          calendar.setTime(date);
97          calendar.set(Calendar.HOUR_OF_DAY, 23);
98          calendar.set(Calendar.MINUTE, 59);
99          calendar.set(Calendar.SECOND, 59);
100         calendar.set(Calendar.MILLISECOND, 0);
101         return calendar.getTime();
102     }
103 
104     /**
105      * reset to 00h00m00s (and 0 millisecond)
106      *
107      * @param date a {@link Date} object.
108      * @param timezone a {@link TimeZone} object.
109      * @return a {@link Date} object.
110      */
111     public static Date resetTime(Date date, TimeZone timezone) {
112         Calendar localCalendar = Calendar.getInstance();
113         localCalendar.setTime(date);
114 
115         Calendar calendar = timezone != null ? Calendar.getInstance(timezone) : Calendar.getInstance();
116         calendar.set(Calendar.DAY_OF_MONTH, localCalendar.get(Calendar.DAY_OF_MONTH));
117         calendar.set(Calendar.MONTH, localCalendar.get(Calendar.MONTH));
118         calendar.set(Calendar.YEAR, localCalendar.get(Calendar.YEAR));
119         resetTime(calendar);
120 
121         return calendar.getTime();
122     }
123 
124     /**
125      * reset to 00h00m00s (and 0 millisecond)
126      *
127      * @param date a {@link Date} object.
128      * @return a {@link Date} object.
129      */
130     public static Date resetTime(Date date) {
131         return resetTime(date, null);
132     }
133 
134     /**
135      * reset to 00h00m00s (and 0 millisecond)
136      *
137      * @param calendar a {@link Calendar} object.
138      * @return a {@link Calendar} object.
139      */
140     public static Calendar resetTime(Calendar calendar) {
141         if (calendar == null) return null;
142         calendar.set(Calendar.HOUR_OF_DAY, 0);
143         calendar.set(Calendar.MINUTE, 0);
144         calendar.set(Calendar.SECOND, 0);
145         calendar.set(Calendar.MILLISECOND, 0);
146 
147         return calendar;
148     }
149 
150     /**
151      * reset to 0 millisecond
152      *
153      * @param date a {@link Timestamp} object.
154      * @return a {@link Timestamp} object.
155      */
156     public static Timestamp resetMillisecond(Timestamp date) {
157         if (date == null) return null;
158         Calendar calendar = Calendar.getInstance();
159         calendar.setTime(date);
160         calendar.set(Calendar.MILLISECOND, 0);
161 
162         return new Timestamp(calendar.getTimeInMillis());
163     }
164 
165     /**
166      * reset to 0 millisecond
167      *
168      * @param date a {@link Date} object.
169      * @return a {@link Timestamp} object.
170      */
171     public static Timestamp resetMillisecond(Date date) {
172         if (date == null) return null;
173         Calendar calendar = Calendar.getInstance();
174         calendar.setTime(date);
175         calendar.set(Calendar.MILLISECOND, 0);
176 
177         return new Timestamp(calendar.getTime().getTime());
178     }
179 
180     /**
181      * reset to 0 millisecond
182      *
183      * @param calendar a {@link Calendar} object.
184      * @return a {@link Calendar} object.
185      */
186     public static Calendar resetMillisecond(Calendar calendar) {
187         calendar.set(Calendar.MILLISECOND, 0);
188 
189         return calendar;
190     }
191 
192     /**
193      * <p>getDifferenceInDays.</p>
194      *
195      * @param startDate a {@link Date} object.
196      * @param endDate a {@link Date} object.
197      * @return a int.
198      */
199     public static int getDifferenceInDays(Date startDate, Date endDate) {
200     	return DateUtil.getDifferenceInDays(startDate, endDate);
201     }
202 
203     /**
204      * <p>formatDate.</p>
205      *
206      * @param date a {@link Date} object.
207      * @param pattern a {@link String} object.
208      * @return a {@link String} object.
209      */
210     public static String formatDate(Date date, String pattern) {
211         if (date == null) return null;
212         SimpleDateFormat simpleDateFormat = new SimpleDateFormat(pattern);
213         return simpleDateFormat.format(date);
214     }
215 
216     /**
217      * Convert to a date, or return null if parse error
218      *
219      * @param date a {@link String} object.
220      * @param pattern a {@link String} object.
221      * @return a {@link Date} object.
222      */
223     public static Date safeParseDate(String date, String pattern) {
224         Date result = null;
225         if (StringUtils.isNotBlank(date)) {
226             try {
227                 SimpleDateFormat simpleDateFormat = new SimpleDateFormat(pattern);
228                 result = simpleDateFormat.parse(date);
229             } catch (ParseException ignored) {
230             }
231         }
232         return result;
233     }
234 
235     /**
236      * Convert to a date, or return null if parse error
237      *
238      * @param date a {@link String} object.
239      * @param patterns a {@link String} object.
240      * @return a {@link Date} object.
241      */
242     public static Date safeParseDate(String date, String... patterns) {
243         Date result = null;
244         if (StringUtils.isNotBlank(date)) {
245             for (String pattern: patterns) {
246                 try {
247                     SimpleDateFormat simpleDateFormat = new SimpleDateFormat(pattern);
248                     result = simpleDateFormat.parse(date);
249                 } catch (ParseException ignored) {
250                     // Continue: try next pattern
251                 }
252             }
253         }
254         return result;
255     }
256 
257     /**
258      * Adds a number of seconds to a date returning a new object.
259      * The original {@code Timestamp} is unchanged.
260      *
261      * @param date  the Timestamp, not null
262      * @param amount  the amount to add, may be negative
263      * @return the new {@code Timestamp} with the amount added
264      * @throws IllegalArgumentException if the date is null
265      */
266     public static Timestamp addSeconds(Timestamp date, int amount) {
267         if(date == null) {
268             throw new IllegalArgumentException("The date must not be null");
269         } else {
270             Calendar c = Calendar.getInstance();
271             c.setTime(date);
272             c.add(Calendar.SECOND, amount);
273             return new Timestamp(c.getTimeInMillis());
274         }
275     }
276 
277     /**
278      * <p>newCreateDate.</p>
279      *
280      * @return a {@link Date} object.
281      */
282     protected Date newCreateDate() {
283         return dateWithNoTime(new Date());
284     }
285 
286     /**
287      * <p>newUpdateTimestamp.</p>
288      *
289      * @return a {@link Timestamp} object.
290      */
291     protected Timestamp newUpdateTimestamp() {
292         return new Timestamp((new Date()).getTime());
293     }
294 
295     /**
296      * <p>dateWithNoTime.</p>
297      *
298      * @param date a {@link Date} object.
299      * @return a {@link Date} object.
300      */
301     protected Date dateWithNoTime(Date date) {
302         Calendar calendar = Calendar.getInstance();
303         calendar.setTime(date);
304         calendar.set(Calendar.HOUR_OF_DAY, 0);
305         calendar.set(Calendar.MINUTE, 0);
306         calendar.set(Calendar.SECOND, 0);
307         calendar.set(Calendar.MILLISECOND, 0);
308         return calendar.getTime();
309     }
310 
311     /**
312      * <p>dateWithNoMillisecond.</p>
313      *
314      * @param date a {@link Date} object.
315      * @return a {@link Date} object.
316      */
317     protected Date dateWithNoMillisecond(Date date) {
318         Calendar calendar = Calendar.getInstance();
319         calendar.setTime(date);
320         calendar.set(Calendar.MILLISECOND, 0);
321         return calendar.getTime();
322     }
323 
324     /**
325      * <p>dateWithNoSecondAndMillisecond.</p>
326      *
327      * @param date a {@link Date} object.
328      * @return a {@link Date} object.
329      */
330     protected Date dateWithNoSecondAndMillisecond(Date date) {
331         Calendar calendar = Calendar.getInstance();
332         calendar.setTime(date);
333         calendar.set(Calendar.SECOND, 0);
334         calendar.set(Calendar.MILLISECOND, 0);
335         return calendar.getTime();
336     }
337 
338     /**
339      * <p>dateWithNoSecondAndOneMillisecond.</p>
340      *
341      * @param date a {@link Date} object.
342      * @return a {@link Date} object.
343      */
344     protected Date dateWithNoSecondAndOneMillisecond(Date date) {
345         Calendar calendar = Calendar.getInstance();
346         calendar.setTime(date);
347         calendar.add(Calendar.SECOND, 0);
348         calendar.add(Calendar.MILLISECOND, 1);
349         return calendar.getTime();
350     }
351 
352     /**
353      * <p>dateWithOneMillisecond.</p>
354      *
355      * @param date a {@link Date} object.
356      * @return a {@link Date} object.
357      */
358     protected Date dateWithOneMillisecond(Date date) {
359         Calendar calendar = Calendar.getInstance();
360         calendar.setTime(date);
361         calendar.add(Calendar.MILLISECOND, 1);
362         return calendar.getTime();
363     }
364 
365     /**
366      * <p>dateOfYearWithOneMillisecond.</p>
367      *
368      * @param year a int.
369      * @return a {@link Date} object.
370      */
371     protected Date dateOfYearWithOneMillisecond(int year) {
372         Calendar calendar = Calendar.getInstance();
373         calendar.setTimeInMillis(0);
374         calendar.set(Calendar.YEAR, year);
375         calendar.set(Calendar.MILLISECOND, 1);
376         return calendar.getTime();
377     }
378 
379     /**
380      * <p>dateOfYearWithOneMillisecondInMillisecond.</p>
381      *
382      * @param year a int.
383      * @return a long.
384      */
385     protected long dateOfYearWithOneMillisecondInMillisecond(int year) {
386         Calendar calendar = Calendar.getInstance();
387         calendar.setTimeInMillis(0);
388         calendar.set(Calendar.YEAR, year);
389         calendar.set(Calendar.MILLISECOND, 1);
390         return calendar.getTimeInMillis();
391     }
392 
393     /**
394      * Test if the date has millisecond set. This yes, return null, then return the date itself.
395      *
396      * @param databaseValue the date stored in the database (could be fake date, not null only because of database constraints)
397      * @return null if the date is a fake date
398      */
399     protected Date convertDatabase2UI(Timestamp databaseValue) {
400         Date result;
401         if (databaseValue == null) {
402             result = null;
403         } else {
404             Calendar calendar = Calendar.getInstance();
405             calendar.setTimeInMillis(databaseValue.getTime());
406             if (calendar.get(Calendar.MILLISECOND) != 0) {
407                 result = null;
408             } else {
409                 result = calendar.getTime();
410             }
411         }
412         return result;
413     }
414 
415     /**
416      * Convert a UI date, when the database value is mandatory.
417      * If the given value is null, use the default date, then set millisecond to '1', to be able to retrieve the null value later.
418      *
419      * @param uiValue the date used in the UI
420      * @return null if the date is a fake date
421      * @param defaultNotEmptyDate a {@link Date} object.
422      * @param addOneSecondToDefaultDate a boolean.
423      */
424     protected Date convertUI2DatabaseMandatoryDate(Date uiValue,
425                                                    Date defaultNotEmptyDate,
426                                                    boolean addOneSecondToDefaultDate) {
427         Date result;
428 
429         // if ui date is not empty, then use it (but reset millisecond)
430         if (uiValue == null) {
431 
432             Preconditions.checkState(
433                     defaultNotEmptyDate != null,
434                     "'defaultNotEmptyDate' could not be null.");
435             Calendar calendar = Calendar.getInstance();
436             calendar.setTime(defaultNotEmptyDate);
437             if (addOneSecondToDefaultDate) {
438                 calendar.add(Calendar.SECOND, 1);
439             }
440             calendar.set(Calendar.MILLISECOND, 1);
441             result = calendar.getTime();
442         } else {
443 
444             result = dateWithNoMillisecond(uiValue);
445         }
446 
447         return result;
448     }
449 
450     public static Date getFirstDayOfYear(int year) {
451         Calendar calendar = Calendar.getInstance();
452         calendar.set(Calendar.YEAR, year);
453         calendar.set(Calendar.DAY_OF_YEAR, 1);
454         resetTime(calendar);
455         return calendar.getTime();
456     }
457     public static Date getLastSecondOfYear(int year) {
458         Calendar calendar = Calendar.getInstance();
459         calendar.set(Calendar.YEAR, year+1);
460         calendar.set(Calendar.DAY_OF_YEAR, 1);
461         resetTime(calendar);
462         calendar.add(Calendar.SECOND, -1);
463         return calendar.getTime();
464     }
465 
466     public static String elapsedTime(long timeInMs) {
467         long elapsedTime = System.currentTimeMillis() - timeInMs;
468         double seconds = (double) elapsedTime / 1_000;
469         return "in " + seconds + "s";
470     }
471 
472 
473 }