/**
*
*/
package com.qprogramming.tasq.support;
import org.joda.time.DateTimeConstants;
import org.joda.time.Duration;
import org.joda.time.Period;
import org.joda.time.field.FieldUtils;
import org.joda.time.format.PeriodFormatter;
import org.joda.time.format.PeriodFormatterBuilder;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import javax.annotation.PostConstruct;
/**
* @author romanjak
* @date 29 maj 2014
*/
@Component
public class PeriodHelper {
private static final PeriodFormatter IN_FORMATER = new PeriodFormatterBuilder()
.appendDays().appendSuffix("d")
.appendHours().appendSuffix("h").appendMinutes().appendSuffix("m")
.toFormatter();
private static final PeriodFormatter OUT_FORMATER = new PeriodFormatterBuilder()
.appendDays().appendSuffix("d ")
.appendHours().appendSuffix("h ").appendMinutes().appendSuffix("m")
.toFormatter();
private static long MILLIS_PER_DAY;
private static int DEFAULT_HOURS_PER_DAY = 8;
@Value("${default.hoursPerDay:8}")
private int hours;
/**
* Returns new Period object fortmated from input ( for example 1w 2d 3h 30m
* )
*
* @param time
* @return
*/
public static Period inFormat(String time) {
if (time == null || "".equals(time)) {
return new Period();
}
Period period = IN_FORMATER.parsePeriod(time.replaceAll("\\s+", ""));
return normalizedStandard(period);
}
/**
* Returns string from period formated in OUT_FORMATER form
*
* @param period
* @return
*/
public static String outFormat(Period period) {
if (period == null) {
period = new Period();
}
return period.toString(OUT_FORMATER);
}
/**
* Adds to periods ( plus standardize based on normals ) TODO change to 8h
* based work day ?
*
* @param period1
* @param period2
* @return
*/
public static Period plusPeriods(Period period1, Period period2) {
Period result = period1.plus(period2);
return normalizedStandard(result);
}
/**
* Subtracts two periods ( plus standardize based on normals )
*
* @param period1
* @param period2
* @return
*/
public static Period minusPeriods(Period period1, Period period2) {
Period result = period1.minus(period2);
return normalizedStandard(result);
}
/**
* Converts period to a duration assuming a 7 day week, application default
* hours day, 60 minute hour and 60 second minute.
* <p>
* This method allows you to convert from a period to a duration. However to
* achieve this it makes the assumption that all weeks are 7 days, all days
* are application default hours, all hours are 60 minutes and all minutes
* are 60 seconds. This is not true when daylight savings time is
* considered, and may also not be true for some unusual chronologies.
* However, it is included as it is a useful operation for many applications
* and business rules.
* <p>
*
* @return a duration equivalent to this period
*/
public static Duration toStandardDuration(Period period) {
long millis = getPeriodMillis(period);
return new Duration(millis);
}
// -----------------------------------------------------------------------
public static Period normalizedStandard(Period period) {
if (MILLIS_PER_DAY == 0) {
MILLIS_PER_DAY = DateTimeConstants.MILLIS_PER_HOUR
* DEFAULT_HOURS_PER_DAY;
}
long millis = getPeriodMillis(period);
Period result = new Period();
// int weeks = (int) (millis / DateTimeConstants.MILLIS_PER_WEEK);
// if (weeks > 0) {
// millis -= (DateTimeConstants.MILLIS_PER_WEEK * weeks);
// result = result.withWeeks(weeks);
// }
int days = (int) (millis / MILLIS_PER_DAY);
if (days > 0) {
millis -= (MILLIS_PER_DAY * days);
result = result.withDays(days);
}
int hours = (int) (millis / DateTimeConstants.MILLIS_PER_HOUR);
if (hours > 0) {
millis -= (DateTimeConstants.MILLIS_PER_HOUR * hours);
result = result.withHours(hours);
}
int minutes = (int) (millis / DateTimeConstants.MILLIS_PER_MINUTE);
result = result.withMinutes(minutes);
int years = period.getYears();
int months = period.getMonths();
if (years != 0 || months != 0) {
years = FieldUtils.safeAdd(years, months / 12);
months = months % 12;
if (years != 0) {
result = result.withYears(years);
}
if (months != 0) {
result = result.withMonths(months);
}
}
return result;
}
/**
* Returns milliseconds from period. Taking in account application property
* default.hoursPerDay and multiplying it by
* DateTimeConstants.MILLIS_PER_HOUR
*
* @param period
* @return
*/
private static long getPeriodMillis(Period period) {
long millis = period.getMillis();
millis += (((long) period.getSeconds()) * ((long) DateTimeConstants.MILLIS_PER_SECOND));
millis += (((long) period.getMinutes()) * ((long) DateTimeConstants.MILLIS_PER_MINUTE));
millis += (((long) period.getHours()) * ((long) DateTimeConstants.MILLIS_PER_HOUR));
millis += (((long) period.getDays()) * MILLIS_PER_DAY);
// millis += (((long) period.getWeeks()) * ((long) DateTimeConstants.MILLIS_PER_WEEK));
return millis;
}
/**
* Set default hours and millis per day , if hours were somehow not present
* in properties , use 8h as default
*/
@PostConstruct
public void init() {
if (hours == 0) {
hours = 8;
}
DEFAULT_HOURS_PER_DAY = hours;
MILLIS_PER_DAY = DateTimeConstants.MILLIS_PER_HOUR * hours;
}
}