View Javadoc
1   /**
2    * Copyright 2004-2014 The Kuali Foundation
3    *
4    * Licensed under the Educational Community License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    *
8    * http://www.opensource.org/licenses/ecl2.php
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   */
16  package org.kuali.kpme.core.util;
17  
18  import org.apache.commons.collections.CollectionUtils;
19  import org.apache.commons.lang.StringUtils;
20  import org.apache.log4j.Logger;
21  import org.joda.time.*;
22  import org.kuali.kpme.core.api.KPMEConstants;
23  import org.kuali.kpme.core.api.assignment.Assignment;
24  import org.kuali.kpme.core.api.assignment.AssignmentDescriptionKey;
25  import org.kuali.kpme.core.api.calendar.entry.CalendarEntry;
26  import org.kuali.kpme.core.api.groupkey.HrGroupKey;
27  import org.kuali.kpme.core.api.util.KpmeUtils;
28  import org.kuali.kpme.core.service.HrServiceLocator;
29  import org.kuali.rice.core.api.config.property.ConfigContext;
30  import org.kuali.rice.core.api.util.RiceKeyConstants;
31  import org.kuali.rice.kim.api.identity.principal.EntityNamePrincipalName;
32  import org.kuali.rice.kim.api.services.KimApiServiceLocator;
33  import org.kuali.rice.krad.util.GlobalVariables;
34  import org.kuali.rice.krad.util.KRADConstants;
35  
36  import javax.servlet.http.HttpServletRequest;
37  import java.math.BigDecimal;
38  import java.net.UnknownHostException;
39  import java.sql.Timestamp;
40  import java.util.*;
41  
42  public class TKUtils {
43  
44      private static final Logger LOG = Logger.getLogger(TKUtils.class);
45  
46      public static boolean singleGroupKeyExists()
47      {
48          if (getSingleGroupKey() != null)
49          {
50              return true;
51          }
52          else
53          {
54              return false;
55          }
56      }
57  
58  
59      public static String getSingleGroupKey(LocalDate asOfDate)
60      {
61          String singleGroupKey = null;
62  
63          List<? extends HrGroupKey> groupKeyList = HrServiceLocator.getHrGroupKeyService().getAllActiveHrGroupKeys(asOfDate);
64          if((CollectionUtils.isNotEmpty(groupKeyList)) && (groupKeyList.size() == 1)) {
65              singleGroupKey = groupKeyList.get(0).getGroupKeyCode();
66          }
67  
68          return singleGroupKey;
69      }
70  
71      public static String getSingleGroupKey()
72      {
73          return getSingleGroupKey(LocalDate.now());
74      }
75  
76      /**
77       * @param dateString the format has to be mm/dd/yyyy
78       * @return dayOfMonth
79       */
80      public static String getDayOfMonthFromDateString(String dateString) {
81          String[] date = dateString.split("/");
82          return date[1];
83      }
84  
85      public static String getSystemTimeZone() {
86          String configTimezone = TimeZone.getDefault().getID();
87          if (ConfigContext.getCurrentContextConfig() != null
88                  && StringUtils.isNotBlank(ConfigContext.getCurrentContextConfig().getProperty(KPMEConstants.ConfigSettings.KPME_SYSTEM_TIMEZONE).trim())) {
89              String tempTimeZoneId = ConfigContext.getCurrentContextConfig().getProperty(KPMEConstants.ConfigSettings.KPME_SYSTEM_TIMEZONE);
90  
91              if (TimeZone.getTimeZone(tempTimeZoneId) != null) {
92                  configTimezone = ConfigContext.getCurrentContextConfig().getProperty(KPMEConstants.ConfigSettings.KPME_SYSTEM_TIMEZONE);
93              } else {
94                  LOG.error("Timezone set by configuration parameter " + KPMEConstants.ConfigSettings.KPME_SYSTEM_TIMEZONE + " is not a valid time zone id.  Using the systems default time zone instead.");
95              }
96          }
97  
98  
99          return configTimezone;
100     }
101 
102     public static DateTimeZone getSystemDateTimeZone() {
103         return DateTimeZone.forID(TKUtils.getSystemTimeZone());
104     }
105 
106     public static final LocalDate END_OF_TIME = new LocalDate(9999, 12, 31);
107 
108     public static long getDaysBetween(LocalDate startDate, LocalDate endDate) {
109     	long daysBetween = 0;
110     	
111     	LocalDate currentDate = startDate;
112         while (currentDate.isBefore(endDate)) {
113             daysBetween++;
114             currentDate = currentDate.plusDays(1);
115         }
116         
117         return daysBetween;
118     }
119 
120     public static BigDecimal getHoursBetween(long start, long end) {
121         long diff = end - start;
122         BigDecimal hrsReminder = new BigDecimal((diff / 3600000.0) % 24);
123         // if the hours is exact duplicate of 24 hours
124         if (hrsReminder.compareTo(BigDecimal.ZERO) == 0 && diff > 0) {
125             return new BigDecimal(diff / 3600000.0).setScale(HrConstants.BIG_DECIMAL_SCALE, HrConstants.BIG_DECIMAL_SCALE_ROUNDING).abs();
126         }
127         return hrsReminder.setScale(HrConstants.BIG_DECIMAL_SCALE, HrConstants.BIG_DECIMAL_SCALE_ROUNDING).abs();
128     }
129 
130     public static BigDecimal getMinutesBetween(DateTime start, DateTime end) {
131         long diff = end.getMillis() - start.getMillis();
132         BigDecimal hrsReminder = new BigDecimal((diff / 3600000.0) % 24);
133         // if the hours is exact duplicate of 24 hours
134         if (hrsReminder.compareTo(BigDecimal.ZERO) == 0 && diff > 0) {
135             return new BigDecimal(diff / 60000.0).setScale(0, HrConstants.BIG_DECIMAL_SCALE_ROUNDING).abs();
136         }
137         BigDecimal min = new BigDecimal((diff / 60000.0));
138         return min.setScale(0, HrConstants.BIG_DECIMAL_SCALE_ROUNDING).abs();
139     }
140 
141     public static BigDecimal getHoursFromMinutes(BigDecimal minutes) {
142         if (minutes == null) {
143             return null;
144         }
145         return minutes.divide(BigDecimal.valueOf(60), HrConstants.MATH_CONTEXT).setScale(HrConstants.BIG_DECIMAL_SCALE, HrConstants.BIG_DECIMAL_SCALE_ROUNDING);
146     }
147 
148 
149     public static Map<String, String> formatAssignmentDescription(Assignment assignment) {
150         Map<String, String> assignmentDescriptions = new LinkedHashMap<String, String>();
151 
152         String assignmentDescKey = KpmeUtils.formatAssignmentKey(assignment.getGroupKeyCode(), assignment.getJobNumber(), assignment.getWorkArea(), assignment.getTask());
153         String assignmentDescValue = HrServiceLocator.getAssignmentService().getAssignmentDescription(assignment.getPrincipalId(), assignment.getGroupKeyCode(), assignment.getJobNumber(), assignment.getWorkArea(), assignment.getTask(), assignment.getEffectiveLocalDate());
154         assignmentDescriptions.put(assignmentDescKey, assignmentDescValue);
155 
156         return assignmentDescriptions;
157     }
158 
159     /**
160      * Constructs a list of Day Spans for the pay calendar entry provided. You
161      * must also provide a DateTimeZone so that we can create relative boundaries.
162      *
163      * @param calendarEntry
164      * @param timeZone
165      * @return
166      */
167     public static List<Interval> getDaySpanForCalendarEntry(CalendarEntry calendarEntry, DateTimeZone timeZone) {
168         DateTime beginDateTime = calendarEntry.getBeginPeriodLocalDateTime().toDateTime(timeZone);
169         DateTime endDateTime = calendarEntry.getEndPeriodLocalDateTime().toDateTime(timeZone);
170 
171         List<Interval> dayIntervals = new ArrayList<Interval>();
172 
173         DateTime currDateTime = beginDateTime;
174         while (currDateTime.isBefore(endDateTime)) {
175             DateTime prevDateTime = currDateTime;
176             currDateTime = currDateTime.plusDays(1);
177             Interval daySpan = new Interval(prevDateTime, currDateTime);
178             dayIntervals.add(daySpan);
179         }
180 
181         return dayIntervals;
182     }
183 
184     public static long convertHoursToMillis(BigDecimal hours) {
185         return hours.multiply(HrConstants.BIG_DECIMAL_MS_IN_H, HrConstants.MATH_CONTEXT).longValue();
186     }
187 
188     public static BigDecimal convertMillisToHours(long millis) {
189         return (new BigDecimal(millis)).divide(HrConstants.BIG_DECIMAL_MS_IN_H, HrConstants.MATH_CONTEXT);
190     }
191 
192     public static BigDecimal convertMillisToMinutes(long millis) {
193         return (new BigDecimal(millis)).divide(HrConstants.BIG_DECIMAL_MS_IN_M, HrConstants.MATH_CONTEXT);
194     }
195     
196     public static BigDecimal convertMillisToDays(long millis) {
197         BigDecimal hrs = convertMillisToHours(millis);
198         return hrs.divide(HrConstants.BIG_DECIMAL_HRS_IN_DAY, HrConstants.MATH_CONTEXT);
199     }
200 
201     public static BigDecimal convertMinutesToHours(BigDecimal minutes) {
202         return minutes.divide(HrConstants.BIG_DECIMAL_60, HrConstants.MATH_CONTEXT);
203     }
204 
205     public static int convertMillisToWholeDays(long millis) {
206         BigDecimal days = convertMillisToDays(millis);
207         return Integer.parseInt(days.setScale(0, BigDecimal.ROUND_UP).toString());
208     }
209 
210     /*
211       * Compares and confirms if the start of the day is at midnight or on a virtual day boundary
212       * returns true if at midnight false otherwise(assuming 24 hr days)
213       */
214     public static boolean isVirtualWorkDay(DateTime beginPeriodDateTime) {
215         return (beginPeriodDateTime.getHourOfDay() != 0 || beginPeriodDateTime.getMinuteOfHour() != 0
216                 && beginPeriodDateTime.get(DateTimeFieldType.halfdayOfDay()) != DateTimeConstants.AM);
217     }
218 
219     /**
220      * Creates a Timestamp object using Jodatime as an intermediate data structure
221      * from the provided date and time string. (From the form POST and javascript
222      * formats)
223      *
224      * @param dateStr (the format is 01/01/2011)
225      * @param timeStr (the format is 8:0)
226      * @return Timestamp
227      */
228     public static DateTime convertDateStringToDateTime(String dateStr, String timeStr) {
229         // the date/time format is defined in tk.calendar.js. For now, the format is 11/17/2010 8:0
230         String[] date = dateStr.split("/");
231         String[] time = timeStr.split(":");
232 
233         DateTimeZone dtz = DateTimeZone.forID(HrServiceLocator.getTimezoneService().getTargetUserTimezone());
234 
235         // this is from the jodattime javadoc:
236         // DateTime(int year, int monthOfYear, int dayOfMonth, int hourOfDay, int minuteOfHour, int secondOfMinute, int millisOfSecond, DateTimeZone zone)
237         // Noted that the month value is the actual month which is different than the java date object where the month value is the current month minus 1.
238         // I tried to use the actual month in the code as much as I can to reduce the convertions.
239         DateTime dateTime = new DateTime(
240                 Integer.parseInt(date[2]),
241                 Integer.parseInt(date[0]),
242                 Integer.parseInt(date[1]),
243                 Integer.parseInt(time[0]),
244                 Integer.parseInt(time[1]),
245                 0, 0, dtz);
246 
247         return dateTime;
248     }
249     
250     public static DateTime convertDateStringToDateTimeWithTimeZone(String dateStr, String timeStr, DateTimeZone dtz) {
251         // the date/time format is defined in tk.calendar.js. For now, the format is 11/17/2010 8:0
252         String[] date = dateStr.split("/");
253         String[] time = timeStr.split(":");
254 
255         // this is from the jodattime javadoc:
256         // DateTime(int year, int monthOfYear, int dayOfMonth, int hourOfDay, int minuteOfHour, int secondOfMinute, int millisOfSecond, DateTimeZone zone)
257         // Noted that the month value is the actual month which is different than the java date object where the month value is the current month minus 1.
258         // I tried to use the actual month in the code as much as I can to reduce the convertions.
259         DateTime dateTime = new DateTime(
260                 Integer.parseInt(date[2]),
261                 Integer.parseInt(date[0]),
262                 Integer.parseInt(date[1]),
263                 Integer.parseInt(time[0]),
264                 Integer.parseInt(time[1]),
265                 0, 0, dtz);
266 
267         return dateTime;
268     }
269     
270     public static DateTime convertDateStringToDateTimeWithoutZone(String dateStr, String timeStr) {
271         // the date/time format is defined in tk.calendar.js. For now, the format is 11/17/2010 8:0
272         String[] date = dateStr.split("/");
273         String[] time = timeStr.split(":");
274 
275         // this is from the jodattime javadoc:
276         // DateTime(int year, int monthOfYear, int dayOfMonth, int hourOfDay, int minuteOfHour, int secondOfMinute, int millisOfSecond, DateTimeZone zone)
277         // Noted that the month value is the actual month which is different than the java date object where the month value is the current month minus 1.
278         // I tried to use the actual month in the code as much as I can to reduce the convertions.
279         DateTime dateTime = new DateTime(
280                 Integer.parseInt(date[2]),
281                 Integer.parseInt(date[0]),
282                 Integer.parseInt(date[1]),
283                 Integer.parseInt(time[0]),
284                 Integer.parseInt(time[1]),
285                 0, 0);
286 
287         return dateTime;
288     }
289 
290    public static String getIPAddressFromRequest(String remoteAddress) {
291         // Check for IPv6 addresses - Not sure what to do with them at this point.
292         // TODO: IPv6 - I see these on my local machine.
293         if (remoteAddress.indexOf(':') > -1) {
294             LOG.warn("ignoring IPv6 address for clock-in: " + remoteAddress);
295             remoteAddress = "";
296         }
297 
298         return remoteAddress;
299     }
300 
301     public static String getIPNumber() {
302         try {
303             return java.net.InetAddress.getLocalHost().getHostAddress();
304         } catch (UnknownHostException e) {
305             return "unknown";
306         }
307     }
308 
309     public static String getIPAddressFromRequest(HttpServletRequest request) {
310         // Check for IPv6 addresses - Not sure what to do with them at this point.
311         // TODO: IPv6 - I see these on my local machine.
312         String fwdIp = request.getHeader("X-Forwarded-For");
313         if (fwdIp != null) {
314             LOG.info("Forwarded IP: " + fwdIp);
315             return fwdIp;
316         }
317 
318         String ip = request.getRemoteAddr();
319         if (ip.indexOf(':') > -1) {
320             LOG.warn("ignoring IPv6 address for clock-in: " + ip);
321             ip = "";
322         }
323 
324         return ip;
325     }
326 
327     //Used to preserve active row fetching based on max(timestamp)
328     public static Timestamp subtractOneSecondFromTimestamp(Timestamp originalTimestamp) {
329         DateTime dt = new DateTime(originalTimestamp);
330         dt = dt.minusSeconds(1);
331         return new Timestamp(dt.getMillis());
332     }
333 
334     public static String formatDate(LocalDate localDate) {
335         if (localDate == null) {
336             return StringUtils.EMPTY;
337         }
338         return HrConstants.DateTimeFormats.BASIC_DATE_FORMAT.print(localDate);
339     }
340 
341     public static String formatDateTimeShort(DateTime dateTime) {
342         if (dateTime == null) {
343             return StringUtils.EMPTY;
344         }
345         return HrConstants.DateTimeFormats.BASIC_DATE_FORMAT.print(dateTime);
346     }
347     
348     public static String formatDateTimeLong(DateTime dateTime){
349         if (dateTime == null) {
350             return StringUtils.EMPTY;
351         }
352         return HrConstants.DateTimeFormats.BASIC_DATE_FORMAT_WITH_SEC.print(dateTime);
353     }
354 
355     public static String formatDateTimeWithTZ(DateTime dateTime){
356         if (dateTime == null) {
357             return StringUtils.EMPTY;
358         }
359         return HrConstants.DateTimeFormats.FULL_DATE_WITH_TZ.print(dateTime);
360     }
361 
362     public static LocalDate formatDateString(String date){
363         if (StringUtils.isEmpty(date)) {
364             return null;
365         }
366         return HrConstants.DateTimeFormats.BASIC_DATE_FORMAT.parseLocalDate(date);
367     }
368     
369     public static String formatTimeShort(String dateString) {
370         if (StringUtils.isEmpty(dateString)) {
371             return null;
372         }
373         DateTime tempDate = HrConstants.DateTimeFormats.BASIC_DATE_FORMAT_WITH_SEC.parseDateTime(dateString);
374     	return HrConstants.DateTimeFormats.BASIC_TIME_FORMAT.print(tempDate);
375     }
376     
377     public static DateTime formatDateTimeString(String dateTime) {
378         if (StringUtils.isEmpty(dateTime)) {
379             return null;
380         }
381         return HrConstants.DateTimeFormats.BASIC_DATE_FORMAT.parseDateTime(dateTime).withZone(HrServiceLocator.getTimezoneService().getTargetUserTimezoneWithFallback());
382     }
383 
384     public static DateTime formatDateTimeStringNoTimezone(String dateTime) {
385         if (StringUtils.isEmpty(dateTime)) {
386             return null;
387         }
388         try {
389             return HrConstants.DateTimeFormats.BASIC_DATE_FORMAT.parseDateTime(dateTime);
390         } catch (IllegalArgumentException e) {
391             return HrConstants.DateTimeFormats.BASIC_DATE_FORMAT_WITH_SEC.parseDateTime(dateTime);
392         }
393     }
394     
395     /**
396      * Method to obtain the timezone offset string for the specified date time.
397      *
398      * Examples:
399      *
400      * -0500
401      * -0800
402      *
403      * @param date
404      * @return
405      */
406     public static String getTimezoneOffset(DateTime date) {
407         StringBuilder o = new StringBuilder();
408 
409         int offsetms = date.getZone().getOffset(date);
410         boolean negative = offsetms < 0;
411         if (negative) offsetms = offsetms * -1;
412 
413         Period period = new Period(offsetms);
414         if (negative) o.append('-');
415         o.append(StringUtils.leftPad(period.getHours() + "", 2, '0'));
416         o.append(StringUtils.leftPad(period.getMinutes() + "", 2, '0'));
417 
418         return o.toString();
419     }
420 
421     public static String arrayToString(String[] stringArray) {
422         StringBuilder str = new StringBuilder();
423         for (String string : stringArray) {
424             str.append(string);
425         }
426         return str.toString();
427     }
428 
429     /**
430      * Get the session timeout time. If it's not defined in the (local) config file, give it a default time.
431      */
432     public static int getSessionTimeoutTime() {
433         return StringUtils.isBlank(ConfigContext.getCurrentContextConfig().getProperty(KPMEConstants.ConfigSettings.SESSION_TIMEOUT))
434                 ? 2700 :
435                 Integer.parseInt(ConfigContext.getCurrentContextConfig().getProperty(KPMEConstants.ConfigSettings.SESSION_TIMEOUT));
436     }
437     
438     public static Timestamp getCurrentTimestamp() {
439         return new Timestamp(System.currentTimeMillis());
440     }
441     
442     public static List<Interval> createDaySpan(DateTime beginDateTime, DateTime endDateTime, DateTimeZone zone) {
443         beginDateTime = beginDateTime.toDateTime(zone);
444         endDateTime = endDateTime.toDateTime(zone);
445         List<Interval> dayIntervals = new ArrayList<Interval>();
446 
447         DateTime currDateTime = beginDateTime;
448         while (currDateTime.isBefore(endDateTime)) {
449             DateTime prevDateTime = currDateTime;
450             currDateTime = currDateTime.plusDays(1);
451             Interval daySpan = new Interval(prevDateTime, currDateTime);
452             dayIntervals.add(daySpan);
453         }
454 
455         return dayIntervals;
456     }
457     
458     public static List<Interval> getDaySpanForCalendarEntry(CalendarEntry calendarEntry) {
459     	return getDaySpanForCalendarEntry(calendarEntry, HrServiceLocator.getTimezoneService().getTargetUserTimezoneWithFallback());
460     }
461 
462     public static List<Interval> getFullWeekDaySpanForCalendarEntry(CalendarEntry calendarEntry) {
463         return getFullWeekDaySpanForCalendarEntry(calendarEntry, HrServiceLocator.getTimezoneService().getTargetUserTimezoneWithFallback());
464     }
465     
466     public static List<Interval> getFullWeekDaySpanForCalendarEntry(CalendarEntry calendarEntry, DateTimeZone timeZone) {
467         DateTime beginDateTime = calendarEntry.getBeginPeriodLocalDateTime().toDateTime(timeZone);
468         DateTime endDateTime = calendarEntry.getEndPeriodLocalDateTime().toDateTime(timeZone);
469 
470         List<Interval> dayIntervals = new ArrayList<Interval>();
471 
472         DateTime currDateTime = beginDateTime;
473         if (beginDateTime.getDayOfWeek() != 7) {
474             currDateTime = beginDateTime.plusDays(0 - beginDateTime.getDayOfWeek());
475         }
476 
477         int afterEndDate = 6 - endDateTime.getDayOfWeek();
478         if (endDateTime.getDayOfWeek() == 7 && endDateTime.getHourOfDay() != 0) {
479             afterEndDate = 6;
480         }
481         if (endDateTime.getHourOfDay() == 0) {
482             afterEndDate += 1;
483         }
484         DateTime aDate = endDateTime.plusDays(afterEndDate);
485         while (currDateTime.isBefore(aDate)) {
486             DateTime prevDateTime = currDateTime;
487             currDateTime = currDateTime.plusDays(1);
488             Interval daySpan = new Interval(prevDateTime, currDateTime);
489             dayIntervals.add(daySpan);
490         }
491 
492         return dayIntervals;
493     }
494     
495     public static int getWorkDays(DateTime startDate, DateTime endDate) {
496     	int workDays = 0;
497 
498 		DateTime currentDate = startDate;
499 		while (!currentDate.isAfter(endDate)) {
500 			if (!isWeekend(currentDate)) {
501 				workDays++;		
502 			}
503 			currentDate = currentDate.plusDays(1);
504 		}
505 		
506     	return workDays;
507     }
508     
509     public static boolean isWeekend(DateTime date) {
510     	return date.getDayOfWeek() == DateTimeConstants.SATURDAY || date.getDayOfWeek() == DateTimeConstants.SUNDAY;
511     }
512     
513     /**
514      * Returns effectiveDate "from" date that's passed in through dateString.
515      * 
516 	 * The "from" dateString can either be from the format "fromDate..toDate" or ">=fromDate", otherwise an empty string is returned.
517 	 * 
518      * @param dateString
519      * @return
520      */
521     public static String getFromDateString(String dateString) {
522     	String fromDateString = StringUtils.EMPTY;
523     	
524     	if (StringUtils.startsWith(dateString, ">=")) {
525     		fromDateString = StringUtils.substringAfter(dateString, ">=");
526     	} else if (StringUtils.contains(dateString, "..")) {
527     		fromDateString = StringUtils.substringBefore(dateString, "..");
528 		}
529     	
530     	return fromDateString;
531     }
532     
533     /**
534      * Returns effectiveDate "to" date that's passed in through dateString.
535      * 
536      * The "to" dateString can either be from the format "fromDate..toDate" or "<=toDate", otherwise an empty string is returned.
537      *
538      * @param dateString
539      * @return
540      */
541     public static String getToDateString(String dateString) {
542     	String toDateString = StringUtils.EMPTY;
543     	
544     	if (StringUtils.startsWith(dateString, "<=")) {
545     		toDateString = StringUtils.substringAfter(dateString, "<=");
546     	} else if (StringUtils.contains(dateString, "..")) {
547     		toDateString = StringUtils.substringAfter(dateString, "..");
548 		}
549     	
550     	return toDateString;
551     }
552     
553 	 
554 	 public static boolean isDateEqualOrBetween(DateTime date, String searchDateString) {
555 		 boolean valid = false;
556 		
557 		 String fromDateString = TKUtils.getFromDateString(searchDateString);
558 		 DateTime fromDate = TKUtils.formatDateTimeString(fromDateString);
559 		 String toDateString = TKUtils.getToDateString(searchDateString);
560 		 DateTime toDate = TKUtils.formatDateTimeString(toDateString);
561 		 
562 		 if (date != null) {
563 			 
564 			 if (fromDate != null ? (date.isEqual(fromDate) || date.isAfter(fromDate)) :
565                      toDate != null ? (date.isBefore(toDate) || date.isEqual(toDate)) : true) {
566 				 valid = true;
567 			 }
568 		 }
569 		 
570 		 return valid;
571 	 }
572 	 
573 	 public static String getRandomColor(Set<String> randomColors) {
574 			String[] letters = "0,1,2,3,4,5,6,7,8,9,A,B,C,D,E,F".split(",");
575 			String color = "#";
576 			for (int i = 0; i < 6; i++) {
577 				int index = (int) Math.round(Math.random() * 15);
578 				color += letters[index];
579 			}
580 			if (randomColors.contains(color)) {
581 				color = getRandomColor(randomColors);
582 			}
583 			return color;
584 	}
585 	 
586 	/*
587 	 * Cleans a numerical input so that it can be successfully used with lookups
588 	 */
589 	public static BigDecimal cleanNumeric( String value ) {
590 		String cleanedValue = value.replaceAll( "[^-0-9.]", "" );
591 		// ensure only one "minus" at the beginning, if any
592 		if ( cleanedValue.lastIndexOf( '-' ) > 0 ) {
593 			if ( cleanedValue.charAt( 0 ) == '-' ) {
594 				cleanedValue = "-" + cleanedValue.replaceAll( "-", "" );
595 			} else {
596 				cleanedValue = cleanedValue.replaceAll( "-", "" );
597 			}
598 		}
599 		// ensure only one decimal in the string
600 		int decimalLoc = cleanedValue.lastIndexOf( '.' );
601 		if ( cleanedValue.indexOf( '.' ) != decimalLoc ) {
602 			cleanedValue = cleanedValue.substring( 0, decimalLoc ).replaceAll( "\\.", "" ) + cleanedValue.substring( decimalLoc );
603 		}
604 		try {
605 			return new BigDecimal( cleanedValue );
606 		} catch ( NumberFormatException ex ) {
607 			GlobalVariables.getMessageMap().putError(KRADConstants.DOCUMENT_ERRORS, RiceKeyConstants.ERROR_CUSTOM, new String[] { "Invalid Numeric Input: " + value });
608 			return null;
609 		}
610 	}
611 	
612 	public static String getDocumentDescription(String principalId, LocalDate effectiveDate) {
613 		StringBuffer docDescription = new StringBuffer();
614 		EntityNamePrincipalName principalName = null;
615         if (principalId != null) {
616             principalName = KimApiServiceLocator.getIdentityService().getDefaultNamesForPrincipalId(principalId);
617         }
618         String personName = (principalName != null  && principalName.getDefaultName() != null) ? principalName.getDefaultName().getCompositeName() : StringUtils.EMPTY;
619         String date = TKUtils.formatDate(effectiveDate);
620         docDescription.append(personName + " (" + principalId + ")  - " + date);
621 		return docDescription.toString();
622 	}
623 	
624 	/*
625 	 * aDateTime is the dateTime we would like to display in the fromTimeZone. 
626 	 * The results of the method is the time showing in the toTimeZone considering the time difference between these two time zones
627 	 */
628 	public static DateTime convertTimeForDifferentTimeZone(DateTime aDateTime, DateTimeZone fromTimeZone, DateTimeZone toTimeZone) {
629 		if(fromTimeZone == null || toTimeZone == null || fromTimeZone.equals(toTimeZone))
630 			return aDateTime;	// no conversion is needed
631 		
632 		Long millisOfSysTime = fromTimeZone.getMillisKeepLocal(toTimeZone, aDateTime.getMillis());
633 		DateTime toTime = new DateTime(millisOfSysTime);
634 		
635 		return toTime;
636 	}
637 	
638 	public static DateTime convertDateTimeToDifferentTimezone(DateTime aDateTime, DateTimeZone fromTimeZone, DateTimeZone toTimeZone) {
639 		if(fromTimeZone == null || toTimeZone == null || fromTimeZone.equals(toTimeZone))
640 			return aDateTime;	// no conversion is needed
641 		
642 		Long millisOfSysTime = toTimeZone.getMillisKeepLocal(fromTimeZone, aDateTime.getMillis());
643 		DateTime toTime = new DateTime(millisOfSysTime);
644 		
645 		return toTime;
646 	}
647 
648 
649     public static Assignment getAssignmentWithKey(List<Assignment> assignments, AssignmentDescriptionKey assignmentDescriptionKey) {
650 
651         for (Assignment assignment : assignments) {
652             if (StringUtils.equals(assignment.getGroupKeyCode(), assignmentDescriptionKey.getGroupKeyCode()) &&
653                     assignment.getJobNumber().compareTo(assignmentDescriptionKey.getJobNumber()) == 0 &&
654                     assignment.getWorkArea().compareTo(assignmentDescriptionKey.getWorkArea()) == 0 &&
655                     assignment.getTask().compareTo(assignmentDescriptionKey.getTask()) == 0) {
656                 return assignment;
657             }
658         }
659 
660         return null;
661     }
662 
663 
664 
665 }