1 /*
2 * #%L
3 * Nuiton Utils
4 * %%
5 * Copyright (C) 2004 - 2010 CodeLutin
6 * %%
7 * This program is free software: you can redistribute it and/or modify
8 * it under the terms of the GNU Lesser General Public License as
9 * published by the Free Software Foundation, either version 3 of the
10 * License, or (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Lesser Public License for more details.
16 *
17 * You should have received a copy of the GNU General Lesser Public
18 * License along with this program. If not, see
19 * <http://www.gnu.org/licenses/lgpl-3.0.html>.
20 * #L%
21 */
22
23 package org.nuiton.util;
24
25 import java.text.DateFormat;
26 import java.text.DateFormatSymbols;
27 import java.text.ParseException;
28 import java.text.SimpleDateFormat;
29 import java.time.LocalDate;
30 import java.time.Period;
31 import java.time.ZoneId;
32 import java.util.Calendar;
33 import java.util.Date;
34 import java.util.Locale;
35
36 /**
37 * Library for manipulating dates.
38 * <p>
39 * <b>Note: </b>
40 *
41 * @author fdesbois
42 * @since 1.4.1
43 */
44 public class DateUtil {
45
46 public static final String DEFAULT_PATTERN = "dd/MM/yyyy";
47
48 public static final String MONTH_PATTERN = "MM/yyyy";
49
50 /**
51 * Format a date using the pattern in argument. The pattern is the same using
52 * for DateFormat object.
53 *
54 * @param date the date to format
55 * @param pattern the pattern to use
56 * @return a String corresponding to the date formatted
57 * @see DateFormat
58 */
59 public static String formatDate(Date date, String pattern) {
60 SimpleDateFormat simpleDateFormat = new SimpleDateFormat(pattern);
61 return simpleDateFormat.format(date);
62 }
63
64 public static String formatDate(Date date, String pattern, Locale locale) {
65 SimpleDateFormat simpleDateFormat = new SimpleDateFormat(pattern, locale);
66 return simpleDateFormat.format(date);
67 }
68
69 /**
70 * Parse a date using the pattern in argument. The pattern is the same using
71 * for DateFormat object.
72 *
73 * @param date the String to parse
74 * @param pattern the pattern to use
75 * @return a Date corresponding to the String argument parsed
76 * @throws ParseException for parsing errors
77 * @see DateFormat
78 */
79 public static Date parseDate(String date, String pattern) throws ParseException {
80 SimpleDateFormat simpleDateFormat = new SimpleDateFormat(pattern);
81 Date result = simpleDateFormat.parse(date);
82 return result;
83 }
84
85 /**
86 * Create a new date from day, month and year (French version).
87 * The month is the real month of the year and not the one which is stored
88 * in Calendar object.
89 *
90 * @param s value of the seconds 1-60
91 * @param m value of the minutes 1-60
92 * @param h value of the hours 1-24
93 * @param dd value of the day 1-31
94 * @param mm value of the month 1-12
95 * @param yy value of the year 0-9999
96 * @return a new date
97 */
98 public static Date createDate(int s, int m, int h, int dd, int mm, int yy) {
99 Calendar calendar = Calendar.getInstance();
100 calendar.setTimeInMillis(0L);
101 calendar.set(Calendar.YEAR, yy);
102 calendar.set(Calendar.MONTH, mm - 1);
103 calendar.set(Calendar.DAY_OF_MONTH, dd);
104 calendar.set(Calendar.HOUR_OF_DAY, h);
105 calendar.set(Calendar.MINUTE, m);
106 calendar.set(Calendar.SECOND, s);
107 return calendar.getTime();
108 }
109
110 /**
111 * Create a new date from day, month and year (French version).
112 * The month is the real month of the year and not the one which is stored
113 * in Calendar object. Time is set to 00:00:00.000
114 *
115 * @param dd value of the day 1-31
116 * @param mm value of the month 1-12
117 * @param yy value of the year 0-9999
118 * @return a new date
119 */
120 public static Date createDate(int dd, int mm, int yy) {
121 Calendar calendar = Calendar.getInstance();
122 calendar.set(Calendar.YEAR, yy);
123 calendar.set(Calendar.MONTH, mm - 1);
124 calendar.set(Calendar.DAY_OF_MONTH, dd);
125 return setMinTimeOfDay(calendar.getTime());
126 }
127
128 /**
129 * Create a new date after the current date (today) with modification on day, month and year.
130 * You can use negative values on arguments to have a date before today.
131 *
132 * @param ddStep nb days you want to increase from the current date
133 * @param mmStep nb months you want to increase from the current date
134 * @param yyStep nb years you want to increase from the current date
135 * @return a new date from the current date increase by days, months and years.
136 */
137 public static Date createDateAfterToday(int ddStep, int mmStep, int yyStep) {
138 Calendar calendar = getDefaultCalendar(new Date());
139 calendar.add(Calendar.DAY_OF_MONTH, ddStep);
140 calendar.add(Calendar.MONTH, mmStep);
141 calendar.add(Calendar.YEAR, yyStep);
142 return calendar.getTime();
143 }
144
145 /**
146 * Set the last day of month to the date in argument.
147 * The value depends on the month of the date. (30 april, 28 february, ...)
148 *
149 * @param date Date to modify
150 * @return the date with day of month modified
151 */
152 public static Date setLastDayOfMonth(Date date) {
153 Calendar calendar = getDefaultCalendar(date);
154 int maximum = calendar.getActualMaximum(Calendar.DAY_OF_MONTH);
155 calendar.set(Calendar.DAY_OF_MONTH, maximum);
156 Date lastDay = calendar.getTime();
157 return lastDay;
158 }
159
160 /**
161 * Set the first day of month to the date in argument.
162 *
163 * @param date Date to modify
164 * @return the date with day of month modified
165 */
166 public static Date setFirstDayOfMonth(Date date) {
167 Calendar calendar = getDefaultCalendar(date);
168 calendar.set(Calendar.DAY_OF_MONTH, 1);
169 Date firstDay = calendar.getTime();
170 return firstDay;
171 }
172
173 /**
174 * Set the last day of year to the date in argument.
175 *
176 * @param date Date to modify
177 * @return the date with day of year modified
178 */
179 public static Date setLastDayOfYear(Date date) {
180 Calendar calendar = getDefaultCalendar(date);
181 int maximum = calendar.getActualMaximum(Calendar.DAY_OF_YEAR);
182 calendar.set(Calendar.DAY_OF_YEAR, maximum);
183 Date lastDay = calendar.getTime();
184 return lastDay;
185 }
186
187 /**
188 * Set the first day of year to the date in argument.
189 *
190 * @param date Date to modify
191 * @return the date with day of year modified
192 */
193 public static Date setFirstDayOfYear(Date date) {
194 Calendar calendar = getDefaultCalendar(date);
195 calendar.set(Calendar.DAY_OF_YEAR, 1);
196 Date firstDay = calendar.getTime();
197 return firstDay;
198 }
199
200 /**
201 * Set the min time of the day : 00:00:00.000.
202 *
203 * @param date to modify
204 * @return Date with the time set to the minimum in the day
205 */
206 public static Date setMinTimeOfDay(Date date) {
207 Calendar calendar = getDefaultCalendar(date);
208 calendar.set(Calendar.AM_PM, Calendar.AM);
209 calendar.set(Calendar.HOUR, 0);
210 calendar.set(Calendar.MINUTE, 0);
211 calendar.set(Calendar.SECOND, 0);
212 calendar.set(Calendar.MILLISECOND, 0);
213 return calendar.getTime();
214 }
215
216 /**
217 * Set the max time of the day. EUROPE : 23:59:59.999.
218 *
219 * @param date to modify
220 * @return Date with the time set to the maximum in the day
221 */
222 public static Date setMaxTimeOfDay(Date date) {
223 Calendar calendar = getDefaultCalendar(date);
224 calendar.set(Calendar.AM_PM, Calendar.PM);
225 calendar.set(Calendar.HOUR, 11);
226 calendar.set(Calendar.MINUTE, 59);
227 calendar.set(Calendar.SECOND, 59);
228 calendar.set(Calendar.MILLISECOND, 999);
229 return calendar.getTime();
230 }
231
232 /**
233 * Check if the first date in argument is included between the two other
234 * dates. The argument myDate can be equals to beforeDate or afterDate to
235 * validate the includes.
236 *
237 * @param myDate the date to test
238 * @param beforeDate the first date of the period to test
239 * @param afterDate the second date of the period to test
240 * @return true if myDate is included between beforeDate and afterDate
241 */
242 public static boolean between(Date myDate, Date beforeDate, Date afterDate) {
243 if (myDate == null) {
244 return false;
245 }
246 boolean result = true;
247 result &= myDate.after(beforeDate) || myDate.compareTo(beforeDate) == 0;
248 result &= afterDate == null || myDate.before(afterDate) ||
249 myDate.compareTo(afterDate) == 0;
250 return result;
251 }
252
253 /**
254 * Check if the current date is between the two dates in argument.
255 *
256 * @param beforeDate the first date of the period
257 * @param afterDate the second date of the period
258 * @return true if the current date is included between the two dates,
259 * false otherwise
260 * @see #between(Date, Date, Date)
261 */
262 public static boolean currentPeriod(Date beforeDate, Date afterDate) {
263 return between(new Date(), beforeDate, afterDate);
264 }
265
266 /**
267 * Get the month value from a date (between 0 and 11).
268 *
269 * @param date the date to extract month
270 * @return the month value of the date
271 */
272 public static int getMonth(Date date) {
273 Calendar calendar = getDefaultCalendar(date);
274 return calendar.get(Calendar.MONTH);
275 }
276
277 /**
278 * Do the difference between the two dates in argument. The result is a number
279 * of seconds between the two dates.
280 *
281 * @param beginDate first date
282 * @param endDate second date
283 * @return a number of seconds between beginDate and endDate
284 */
285 public static int getDifferenceInSeconds(Date beginDate, Date endDate) {
286 long begin = beginDate.getTime();
287 long end = endDate.getTime();
288 return (int) Math.ceil((end - begin) / 1000);
289 }
290
291 /**
292 * Do the difference between the two dates in argument. The result is a number
293 * of minutes between the two dates.
294 *
295 * @param beginDate first date
296 * @param endDate second date
297 * @return a number of minutes between beginDate and endDate
298 */
299 public static int getDifferenceInMinutes(Date beginDate, Date endDate) {
300 long begin = beginDate.getTime();
301 long end = endDate.getTime();
302 // 60000 = 60 * 1000
303 return (int) Math.ceil((end - begin) / 60000);
304 }
305
306 /**
307 * Do the difference between the two dates in argument. The result is a number
308 * of hours between the two dates.
309 *
310 * @param beginDate first date
311 * @param endDate second date
312 * @return a number of hours between beginDate and endDate
313 */
314 public static int getDifferenceInHours(Date beginDate, Date endDate) {
315 long begin = beginDate.getTime();
316 long end = endDate.getTime();
317 // 3600000 = 60 * 60 * 1000
318 return (int) Math.ceil((end - begin) / 3600000);
319 }
320
321 /**
322 * Do the difference between the two dates in argument. The result is a number
323 * of days between the two dates.
324 * Ex : 28/01/2009 and 08/02/2009 return 11.
325 *
326 * @param beginDate first date
327 * @param endDate second date
328 * @return a number of days between beginDate and endDate
329 */
330 public static int getDifferenceInDays(Date beginDate, Date endDate) {
331
332 LocalDate beginLocalDate = beginDate.toInstant().atZone(ZoneId.systemDefault()).toLocalDate();
333 LocalDate endLocalDate = endDate.toInstant().atZone(ZoneId.systemDefault()).toLocalDate();
334
335 Period period = Period.between(beginLocalDate, endLocalDate);
336 int diff = period.getDays();
337
338 return diff;
339 }
340
341 /**
342 * Do the difference between the two dates in argument. The result is a number
343 * of months between the two dates.
344 * Ex : 01/01/2009 and 28/02/2009 return 2 months.
345 * Warning, if beginDate is inferior to endDate, the result will be 1 minimum
346 *
347 * @param beginDate first date
348 * @param endDate second date
349 * @return a number of months between beginDate and endDate
350 */
351 public static int getDifferenceInMonths(Date beginDate, Date endDate) {
352 int count = 0;
353 Calendar fromCalendar = getDefaultCalendar(beginDate);
354 Calendar thruCalendar = getDefaultCalendar(endDate);
355
356 while (fromCalendar.before(thruCalendar)) {
357 fromCalendar.add(Calendar.MONTH, 1);
358 count++;
359 }
360 return count;
361 }
362
363 /**
364 * Get the age of a person born on the date in argument. The result is a number
365 * of years between the birth date and now.
366 * Ex : 01/01/2000 returns 11 years (now date is 26/10/2011).
367 *
368 * @param birthDate birth date
369 * @return a number of years between birthDate and now
370 */
371 public static int getAge(Date birthDate) {
372 int count = 0;
373 Calendar fromCalendar = getDefaultCalendar(birthDate);
374 Calendar thruCalendar = getDefaultCalendar(new Date());
375
376 fromCalendar.add(Calendar.YEAR, 1);
377 while (fromCalendar.before(thruCalendar)) {
378 count++;
379 fromCalendar.add(Calendar.YEAR, 1);
380 }
381 return count;
382 }
383
384 /**
385 * Get libelle of the month corresponding to the number given in argument.
386 *
387 * @param monthNumber between 1-12
388 * @param locale Locale for language support
389 * @return a String corresponding to the libelle of the month
390 */
391 public static String getMonthLibelle(int monthNumber, Locale locale) {
392 return new DateFormatSymbols(locale).getMonths()[monthNumber - 1];
393 }
394
395 /**
396 * Get libelle of the month corresponding to the number given in argument.
397 *
398 * @param monthNumber between 1-12
399 * @return a String corresponding to the libelle of the month
400 */
401 public static String getMonthLibelle(int monthNumber) {
402 return getMonthLibelle(monthNumber, Locale.getDefault());
403 }
404
405 /**
406 * Get the date before today
407 *
408 * @param date concerned
409 * @return Date before today
410 */
411 public static Date getYesterday(Date date) {
412 Calendar cal = getDefaultCalendar(date);
413 if (cal.get(Calendar.MONTH) == Calendar.JANUARY && cal.get(Calendar.DAY_OF_MONTH) == 1) {
414 cal.roll(Calendar.YEAR, false);
415 }
416 if (cal.get(Calendar.DAY_OF_MONTH) == 1) {
417 cal.roll(Calendar.MONTH, false);
418 }
419 cal.roll(Calendar.DAY_OF_MONTH, false);
420 return cal.getTime();
421 }
422
423 /**
424 * Get the calendar corresponding to the {@code date}. The default calendar
425 * will be returned (default time zone and locale).
426 *
427 * @param date used to set the calendar time
428 * @return the default calendar with time corresponding to the {@code date}
429 */
430 public static Calendar getDefaultCalendar(Date date) {
431 Calendar calendar = Calendar.getInstance();
432 calendar.setTime(date);
433 return calendar;
434 }
435
436 /**
437 * Truncate a date to its week (to monday). It's equivalent to a call to
438 * {@link org.apache.commons.lang3.time.DateUtils#truncate(Date, int)}
439 * and giving {@link Calendar#DAY_OF_WEEK} argument, but such a call
440 * raise an exception showing that this field is not supported. This method
441 * allows you to bypass this limitation.
442 *
443 * @param date any date
444 * @return a date in the same week as given date, a monday. All field below
445 * (hours, secondes, ms) are zeroed.
446 */
447 public static Date truncateToDayOfWeek(Date date) {
448 Calendar calendar = Calendar.getInstance();
449 calendar.setTime(date);
450 calendar.set(Calendar.DAY_OF_WEEK, Calendar.MONDAY);
451 calendar.set(Calendar.HOUR_OF_DAY, 0);
452 calendar.set(Calendar.MINUTE, 0);
453 calendar.set(Calendar.SECOND, 0);
454 calendar.set(Calendar.MILLISECOND, 0);
455 return calendar.getTime();
456 }
457
458
459 /**
460 * Enleve les données des heures (hour, minute, second, milli = 0).
461 *
462 * @param date la date a modifier
463 * @return la date d'un jour
464 */
465 public static Date getDay(Date date) {
466 Calendar calendar = Calendar.getInstance();
467 calendar.setTime(date);
468 calendar.set(Calendar.MILLISECOND, 0);
469 calendar.set(Calendar.SECOND, 0);
470 calendar.set(Calendar.MINUTE, 0);
471 calendar.set(Calendar.HOUR_OF_DAY, 0);
472 date = calendar.getTime();
473 return date;
474 }
475
476 /**
477 * Positionne une date sur la fin d'un jour
478 *
479 * @param date la date a modifier
480 * @return la date d'un jour
481 */
482 public static Date getEndOfDay(Date date) {
483 Calendar calendar = Calendar.getInstance();
484 calendar.setTime(date);
485 calendar.set(Calendar.MILLISECOND, 999);
486 calendar.set(Calendar.SECOND, 59);
487 calendar.set(Calendar.MINUTE, 59);
488 calendar.set(Calendar.HOUR_OF_DAY, 23);
489 date = calendar.getTime();
490 return date;
491 }
492
493 /**
494 * Créer la date qui utilise le jour donné dans {@code day} et l'heure
495 * donnée dans {@code time}.
496 *
497 * @param day le jour à utiliser
498 * @param time l'heure a utiliser
499 * @param useSecond FIXME
500 * @param useMiliSecond FIXME
501 * @return la date donnée avec l'heure courante
502 */
503 public static Date getDateAndTime(Date day, Date time, boolean useSecond, boolean useMiliSecond) {
504
505 Calendar calendar = Calendar.getInstance();
506
507 // recuperation de l'heure
508 calendar.setTime(time);
509 int h = calendar.get(Calendar.HOUR_OF_DAY);
510 int m = calendar.get(Calendar.MINUTE);
511 int s = useSecond ? calendar.get(Calendar.SECOND) : 0;
512 int ms = useMiliSecond ? calendar.get(Calendar.MILLISECOND) : 0;
513
514 calendar.setTime(day);
515
516 // appliquer l'heure
517 calendar.set(Calendar.HOUR_OF_DAY, h);
518 calendar.set(Calendar.MINUTE, m);
519 calendar.set(Calendar.SECOND, s);
520 calendar.set(Calendar.MILLISECOND, ms);
521
522 return calendar.getTime();
523
524 }
525
526 /**
527 * Créer la date qui utilise uniquement l'heure
528 * donnée dans {@code dayTime}.
529 *
530 * @param dayTime l'heure a utiliser
531 * @param useSecond FIXME
532 * @param useMiliSecond FIXME
533 * @return la date donnée avec uniquement l'heure courante
534 */
535 public static Date getTime(Date dayTime, boolean useSecond, boolean useMiliSecond) {
536 Calendar calendar = Calendar.getInstance();
537
538 // recuperation de l'heure
539 calendar.setTime(dayTime);
540 int h = calendar.get(Calendar.HOUR_OF_DAY);
541 int m = calendar.get(Calendar.MINUTE);
542 int s = calendar.get(Calendar.SECOND);
543 int ms = calendar.get(Calendar.MILLISECOND);
544
545
546 // on part d'une date vide
547 calendar.setTimeInMillis(0);
548
549 // appliquer l'heure
550 calendar.set(Calendar.HOUR_OF_DAY, h);
551 calendar.set(Calendar.MINUTE, m);
552 if (useSecond) {
553 calendar.set(Calendar.SECOND, s);
554 }
555 if (useMiliSecond) {
556 calendar.set(Calendar.MILLISECOND, ms);
557 }
558
559 return calendar.getTime();
560 }
561 }