Update appc-common to Karaf 4
[appc.git] / appc-core / appc-common-bundle / src / main / java / org / onap / appc / util / Time.java
1 /*-
2  * ============LICENSE_START=======================================================
3  * ONAP : APPC
4  * ================================================================================
5  * Copyright (C) 2017-2018 AT&T Intellectual Property. All rights reserved.
6  * ================================================================================
7  * Copyright (C) 2017 Amdocs
8  * =============================================================================
9  * Licensed under the Apache License, Version 2.0 (the "License");
10  * you may not use this file except in compliance with the License.
11  * You may obtain a copy of the License at
12  * 
13  *      http://www.apache.org/licenses/LICENSE-2.0
14  * 
15  * Unless required by applicable law or agreed to in writing, software
16  * distributed under the License is distributed on an "AS IS" BASIS,
17  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18  * See the License for the specific language governing permissions and
19  * limitations under the License.
20  * 
21  * ============LICENSE_END=========================================================
22  */
23
24
25
26 package org.onap.appc.util;
27
28 import java.sql.Timestamp;
29 import java.text.DateFormat;
30 import java.text.ParseException;
31 import java.text.SimpleDateFormat;
32 import java.util.ArrayList;
33 import java.util.Calendar;
34 import java.util.Date;
35 import java.util.GregorianCalendar;
36 import java.util.List;
37 import java.util.Locale;
38 import java.util.SimpleTimeZone;
39 import java.util.TimeZone;
40 import javax.xml.datatype.DatatypeConfigurationException;
41 import javax.xml.datatype.DatatypeFactory;
42 import javax.xml.datatype.XMLGregorianCalendar;
43 import org.slf4j.Logger;
44 import org.slf4j.LoggerFactory;
45
46 /**
47  * This class is a general purpose helper class to augment standard Java time support.
48  *
49  */
50
51 public final class Time {
52
53     /**
54      * Logger to log operations
55      */
56     private static final Logger LOG = LoggerFactory.getLogger(Time.class);
57
58     /**
59      * A formatter to be used to format values
60      */
61     private static SimpleDateFormat dateformatter = null;
62
63     /**
64      * The UTC timezone (for UTC or GMT time)
65      */
66     @SuppressWarnings("nls")
67     private static final TimeZone utcTZ = TimeZone.getTimeZone("UTC");
68
69     /**
70      * The cached reference to the datatype factory
71      */
72     private static DatatypeFactory xmlDatatypeFactory = null;
73
74     /**
75      * Private default constructor prevents instantiation
76      */
77     private Time() {
78         //
79     }
80
81     /**
82      * Increments a date by the indicated months, days, hours, minutes, and seconds, and returns the
83      * updated date.
84      *
85      * @param date The date to be manipulated
86      * @param months The number of months to be added to the date
87      * @param days The number of days to be added to the date
88      * @param hours The number of hours to be added to the date
89      * @param minutes The number of minutes to be added to the date
90      * @param seconds The number of seconds to be added to the date
91      * @return The updated date.
92      */
93     public static Date addTime(final Date date, final int months, final int days, final int hours,
94             final int minutes, final int seconds) {
95         Calendar cal = Calendar.getInstance();
96         cal.setTime(date);
97         cal.add(Calendar.MONTH, months);
98         cal.add(Calendar.DATE, days);
99         cal.add(Calendar.HOUR_OF_DAY, hours);
100         cal.add(Calendar.MINUTE, minutes);
101         cal.add(Calendar.SECOND, seconds);
102         return cal.getTime();
103     }
104
105     /**
106      * Clears the time components of a calendar to zero, leaving the date components unchanged.
107      *
108      * @param cal the calendar to be updated
109      * @return The updated calendar object
110      */
111     public static Calendar dateOnly(final Calendar cal) {
112         cal.set(Calendar.HOUR_OF_DAY, 0);
113         cal.set(Calendar.MINUTE, 0);
114         cal.set(Calendar.SECOND, 0);
115         cal.set(Calendar.MILLISECOND, 0);
116         return cal;
117     }
118
119     /**
120      * This method returns the local time that corresponds to the end of the current day
121      *
122      * @return The time that corresponds to the end of the current day, expressed as local time
123      */
124     public static Date endOfDayLocal() {
125         return endOfDayLocal(new Date());
126     }
127
128     /**
129      * This method returns the last moment of the day for the supplied local time. This is defined
130      * as the millisecond before midnight of the current date represented by the local time.
131      *
132      * @param localTime The local time for which the last moment of the day is desired.
133      * @return The millisecond prior to midnight, local time.
134      */
135     public static Date endOfDayLocal(final Date localTime) {
136         // @sonar:off
137         GregorianCalendar calendar = new GregorianCalendar();
138         calendar.setTime(localTime);
139         calendar.set(Calendar.HOUR, 11);
140         calendar.set(Calendar.AM_PM, Calendar.PM);
141         calendar.set(Calendar.MINUTE, 59);
142         calendar.set(Calendar.SECOND, 59);
143         calendar.set(Calendar.MILLISECOND, 999);
144         // @sonar:on
145
146         return calendar.getTime();
147     }
148
149     /**
150      * The end of the current day and in the current time zone expressed as a UTC time.
151      *
152      * @return The UTC time that corresponds to the end of the current day
153      */
154     public static Date endOfDayUTC() {
155         return endOfDayUTC(new Date());
156     }
157
158     /**
159      * Returns the UTC time that corresponds to the end of the day for the local time specified,
160      * using the current (default) time zone.
161      *
162      * @param localTime The local time for which we are requesting the UTC time that corresponds to
163      *        the end of the day
164      * @return The UTC time that corresponds to the end of the local day specified by the local
165      *         time.
166      */
167     public static Date endOfDayUTC(final Date localTime) {
168         return endOfDayUTC(localTime, TimeZone.getDefault());
169     }
170
171     /**
172      * Returns the time expressed in UTC time of the end of the day specified in local time and
173      * within the local time zone.
174      *
175      * @param localTime The local time for which we will compute the end of the local day, and then
176      *        convert to UTC time.
177      * @param localTimeZone The time zone that the local time is within.
178      * @return The UTC date that corresponds to the end of the day local time and in the local time
179      *         zone.
180      */
181     public static Date endOfDayUTC(final Date localTime, final TimeZone localTimeZone) {
182         Date endOfDay = endOfDayLocal(localTime);
183         return utcDate(endOfDay, localTimeZone);
184     }
185
186     /**
187      * returns current Date in 'UTC' Timezone
188      *
189      * @return The current date, expressed in the UTC timezone.
190      */
191     @SuppressWarnings("nls")
192     public static Date getCurrentUTCDate() {
193
194         // This code incorrectly changes the default timezone for the entire JVM in order to compute
195         // the UTC
196         // date for the current time.
197
198         GregorianCalendar calendar = new GregorianCalendar();
199         calendar.setTimeZone(TimeZone.getTimeZone("UTC"));
200         calendar.setTimeInMillis(utcTime());
201         return calendar.getTime();
202     }
203
204     /**
205      * This method loads and caches the reference to the XML data type factory object.
206      *
207      * @return The XML Data Type Factory object
208      */
209     public static DatatypeFactory getDatatypeFactory() {
210         if (xmlDatatypeFactory == null) {
211             try {
212                 xmlDatatypeFactory = DatatypeFactory.newInstance();
213             } catch (DatatypeConfigurationException e) {
214                 e.printStackTrace(System.err);
215             }
216         }
217         return xmlDatatypeFactory;
218     }
219
220     /**
221      * Gives the date-time String based on given Locale and Timezone
222      *
223      * @param date The date to be formatted
224      * @param locale The locale that we want to format the value for
225      * @param timezone The time zone that the date is within
226      * @return The formatted value
227      */
228     public static String getDateByLocaleAndTimeZone(final Date date, final Locale locale,
229             final TimeZone timezone) {
230         String strDate = null;
231         DateFormat df =
232                 DateFormat.getDateTimeInstance(DateFormat.MEDIUM, DateFormat.MEDIUM, locale);
233         df.setTimeZone(timezone);
234         synchronized (df) {
235             strDate = df.format(date);
236         }
237         return strDate;
238     }
239
240     /**
241      * Returns singleton UTC date formatter.
242      *
243      * @return
244      */
245     @SuppressWarnings("nls")
246     private static SimpleDateFormat getDateFormatter() {
247         if (dateformatter == null) {
248             dateformatter = new SimpleDateFormat("MM/dd/yyyy HH:mm:ss");
249             dateformatter.setTimeZone(new SimpleTimeZone(SimpleTimeZone.UTC_TIME, "UTC"));
250         }
251         return dateformatter;
252     }
253
254     /**
255      * This method returns the local time that corresponds to a given UTC time in the current time
256      * zone.
257      *
258      * @param utcTime The UTC time for which we desire the equivalent local time in the current time
259      *        zone.
260      * @return The local time that is equivalent to the given UTC time for the current time zone
261      */
262     public static long localTime(final long utcTime) {
263         return localTime(utcTime, TimeZone.getDefault());
264     }
265
266     /**
267      * This method can be used to get the local time that corresponds to a specific UTC time.
268      * <p>
269      * This method has a problem since the offset can only be determined by having a local time. So,
270      * we take the UTC time and add the raw offset to it to come up with an approximation of the
271      * local time. This gives us a local time that we can use to determine what the offset should
272      * be, which is what we actually add to the UTC time to get the local time.
273      * </p>
274      *
275      * @param utcTime The UTC time for which we want to obtain the equivalent local time
276      * @param localTZ The time zone that we want the local time to be within
277      * @return The local time for the specified time zone and the given UTC time
278      */
279     public static long localTime(final long utcTime, final TimeZone localTZ) {
280         int offset = localTZ.getOffset(utcTime + localTZ.getRawOffset());
281         long result = utcTime + offset;
282
283         return result;
284     }
285
286     /**
287      * Sets the date components of a calendar to the specified values, leaving the time components
288      * unchanged.
289      *
290      * @param cal The calendar to be updated
291      * @param year The year to be set
292      * @param month The month to be set
293      * @param day The day to be set
294      * @return The updated calendar object
295      */
296     public static Calendar setDate(final Calendar cal, final int year, final int month,
297             final int day) {
298         cal.set(Calendar.YEAR, year);
299         cal.set(Calendar.MONTH, month);
300         cal.set(Calendar.DAY_OF_MONTH, day);
301         return cal;
302     }
303
304     /**
305      * Returns the start of the day expressed in local time for the current local time.
306      *
307      * @return The start of the day
308      */
309     public static Date startOfDayLocal() {
310         return startOfDayLocal(new Date());
311     }
312
313     /**
314      * This method returns the date that corresponds to the start of the day local time. The date
315      * returned represents midnight of the previous day represented in local time. If the UTC time
316      * is desired, use the methods {@link #startOfDayUTC(Date, TimeZone)},
317      * {@link #startOfDayUTC(Date)}, or {@link #startOfDayUTC()}
318      *
319      * @param localTime The local date that we wish to compute the start of day for.
320      * @return The date that corresponds to the start of the local day
321      */
322     public static Date startOfDayLocal(final Date localTime) {
323         GregorianCalendar calendar = new GregorianCalendar();
324         calendar.setTime(localTime);
325         calendar.set(Calendar.HOUR, 0);
326         calendar.set(Calendar.AM_PM, Calendar.AM);
327         calendar.set(Calendar.MINUTE, 0);
328         calendar.set(Calendar.SECOND, 0);
329         calendar.set(Calendar.MILLISECOND, 0);
330
331         return calendar.getTime();
332     }
333
334     /**
335      * This method returns the UTC date that corresponds to the start of the local day based on the
336      * current time and the default time zone (the time zone we are running in).
337      *
338      * @return The start of the local day expressed as a UTC time.
339      */
340     public static Date startOfDayUTC() {
341         return startOfDayUTC(new Date());
342     }
343
344     /**
345      * This method returns the UTC date that corresponds to the start of the local day specified in
346      * the current time zone.
347      *
348      * @param localTime The local time to be used to compute the start of the day
349      * @return The start of the local day expressed as a UTC time.
350      */
351     public static Date startOfDayUTC(final Date localTime) {
352         return startOfDayUTC(localTime, TimeZone.getDefault());
353     }
354
355     /**
356      * This method returns the UTC date that corresponds to the start of the local day specified in
357      * the local timezone.
358      *
359      * @param localTime The local time to be used to compute start of day
360      * @param localTimeZone The time zone that the local time was recorded within
361      * @return The corresponding UTC date
362      */
363     public static Date startOfDayUTC(final Date localTime, final TimeZone localTimeZone) {
364         Date startOfDay = startOfDayLocal(localTime);
365         return utcDate(startOfDay, localTimeZone);
366     }
367
368     /**
369      * This method creates and returns an XML timestamp expressed as the current UTC value for the
370      * system. The caller does not specify the time value or time zone using this method. This
371      * ensures that the timestamp value is always expressed as UTC time.
372      *
373      * @return The XMLGregorianCalendar that can be used to record the timestamp
374      */
375
376     public static XMLGregorianCalendar timestamp() {
377         getDatatypeFactory();
378         XMLGregorianCalendar ts = xmlDatatypeFactory.newXMLGregorianCalendar();
379         GregorianCalendar utc = new GregorianCalendar();
380         utc.setTime(utcDate());
381         ts.setTimezone(0);
382         ts.setYear(utc.get(Calendar.YEAR));
383         // Calendar Months are from 0-11 need to +1
384         ts.setMonth(utc.get(Calendar.MONTH) + 1);
385         ts.setDay(utc.get(Calendar.DAY_OF_MONTH));
386         ts.setHour(utc.get(Calendar.HOUR_OF_DAY));
387         ts.setMinute(utc.get(Calendar.MINUTE));
388         ts.setSecond(utc.get(Calendar.SECOND));
389         ts.setMillisecond(utc.get(Calendar.MILLISECOND));
390         return ts;
391     }
392
393     /**
394      * Converts XMLGregorianCalendar to java.util.Date in Java
395      *
396      * @param calendar the calendar object to be converted
397      * @return The equivalent Date object
398      */
399     public static Date toDate(final XMLGregorianCalendar calendar) {
400         if (calendar == null) {
401             return null;
402         }
403         return calendar.toGregorianCalendar().getTime();
404     }
405
406     /**
407      * Converts java Date to XMLGregorianCalendar.
408      *
409      * @param date The date to convert
410      * @return The XMLGregorianCalendar for the specified date
411      */
412     @SuppressWarnings("nls")
413     public static XMLGregorianCalendar toXMLCalendar(final Date date) {
414         GregorianCalendar cal = (GregorianCalendar) Calendar.getInstance();
415         cal.setTime(date);
416
417         XMLGregorianCalendar xmlCal = null;
418         try {
419             xmlCal = DatatypeFactory.newInstance().newXMLGregorianCalendar(cal);
420         } catch (DatatypeConfigurationException e) {
421             LOG.error("toXMLCalendar", e);
422         }
423         return xmlCal;
424     }
425
426     /**
427      * Truncates the provided date so that only the date, hours, and minutes portions are
428      * significant. This method returns the date with the seconds and milliseconds forced to zero.
429      *
430      * @param date The date to truncate
431      * @return The date with only the year, month, day, hours, and minutes significant.
432      */
433     public static Date truncDate(final Date date) {
434         Calendar cal = Calendar.getInstance();
435         cal.setTime(date);
436         cal.set(Calendar.SECOND, 0);
437         cal.set(Calendar.MILLISECOND, 0);
438         return cal.getTime();
439     }
440
441     /**
442      * The UTC date that corresponds to the current date in the local time zone.
443      *
444      * @return The UTC date for now in the current time zone.
445      */
446     public static Date utcDate() {
447         return new Date();
448     }
449
450     /**
451      * The UTC date for the specified date in the current (default) time zone.
452      *
453      * @param date The local date for which the UTC date is desired.
454      * @return The UTC date that corresponds to the date in the current time zone.
455      */
456     public static Date utcDate(final Date date) {
457         TimeZone tz = TimeZone.getDefault();
458         return utcDate(date, tz);
459     }
460
461     /**
462      * Returns the UTC date for the specified date in the specified time zone.
463      *
464      * @param date The date for which the UTC date is desired in the specified zone
465      * @param tz The time zone that corresponds to the date to be converted to UTC
466      * @return The UTC date that corresponds to the local date in the local time zone.
467      */
468     public static Date utcDate(final Date date, final TimeZone tz) {
469         return new Date(utcTime(date.getTime(), tz));
470     }
471
472     /**
473      * Format incoming date as string in GMT or UTC.
474      *
475      * @param dt The date to be formatted
476      * @return The date formatted for UTC timezone
477      */
478     public static String utcFormat(final Date dt) {
479         String strDate = null;
480         DateFormat df = getDateFormatter();
481         synchronized (df) {
482             strDate = df.format(dt);
483         }
484         return strDate;
485     }
486
487     /**
488      * Parse previously formated Date object back to a Date object.
489      *
490      * @param dateStr The representation of a UTC date as a string
491      * @return The date object containing the parsed representation, or null if the representation
492      *         cannot be parsed
493      */
494     @SuppressWarnings("nls")
495     public static Date utcParse(final String dateStr) {
496         String[] adtl = {"yyyy-MM-dd"};
497         return utcParse(dateStr, adtl);
498     }
499
500     /**
501      * Parse previously formated Date object back to a Date object.
502      *
503      * @param dateStr The representation of a UTC date as a string
504      * @param adtlFormatStrings A list of strings that represent additional date format
505      *        representations to try and parse.
506      * @return The date object containing the parsed representation, or null if the representation
507      *         cannot be parsed
508      */
509     @SuppressWarnings("nls")
510     public static Date utcParse(final String dateStr, String... adtlFormatStrings) {
511         if (dateStr != null) {
512             // Build the list of formatters starting with the default defined in the class
513             List<DateFormat> formats = new ArrayList<>();
514             formats.add(getDateFormatter());
515
516             if (adtlFormatStrings != null) {
517                 for (String s : adtlFormatStrings) {
518                     formats.add(new SimpleDateFormat(s));
519                 }
520             }
521
522             // Return the first matching date formatter's result
523             for (DateFormat df : formats) {
524                 df.setTimeZone(utcTZ);
525                 try {
526                     return df.parse(dateStr);
527                 } catch (ParseException e) {
528                     LOG.debug(String.format("IGNORE - Date string [%s] does not fit pattern [%s]",
529                             dateStr, df.toString()));
530                 }
531             }
532         }
533         return null;
534     }
535
536     /**
537      * This method returns the current time for the UTC timezone
538      *
539      * @return The time in the UTC time zone that corresponds to the current local time.
540      */
541     public static long utcTime() {
542         return new Date().getTime();
543     }
544
545     /**
546      * Get the UTC time that corresponds to the given time in the default time zone (current time
547      * zone for the system).
548      *
549      * @param localTime The time in the current time zone for which the UTC time is desired.
550      * @return The UTC time
551      */
552     public static long utcTime(final long localTime) {
553         TimeZone tz = TimeZone.getDefault();
554         return utcTime(localTime, tz);
555     }
556
557     /**
558      * Get the UTC time that corresponds to the given time in the specified timezone.
559      * <p>
560      * Note that the java <code>getOffset()</code> method works a little counter-intuitive. It
561      * returns the offset that would be added to the current UTC time to get the LOCAL time
562      * represented by the local time zone. That means to get the UTC time, we need to SUBTRACT this
563      * offset from the local time.
564      * </p>
565      *
566      * @param localTime The time in the specified time zone for which the UTC time is desired.
567      * @param localTZ The time zone which the local time is in.
568      * @return The UTC time for the specified local time in the specified local time zone.
569      */
570     public static long utcTime(final long localTime, final TimeZone localTZ) {
571         int offset = localTZ.getOffset(localTime);
572         return localTime - offset;
573
574     }
575
576     /**
577      * Creates a timestamp value from a time
578      *
579      * @param utcTime The UTC time to convert to a timestamp
580      * @return The timestamp
581      */
582     public static Timestamp utcTimestamp(final long utcTime) {
583         TimeZone tz = TimeZone.getDefault();
584         return new Timestamp(utcTime(utcTime, tz));
585     }
586
587     public static String dateToStringConverterMillis(Date date) {
588         SimpleDateFormat customDate = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss:SSS");
589         if (date != null) {
590             return customDate.format(date);
591         }
592         return null;
593     }
594
595     public static Date stringToDateConverterMillis(String dateString) throws ParseException {
596         SimpleDateFormat customDate = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss:SSS");
597         return customDate.parse(dateString);
598     }
599 }