package crmdna.common;
import crmdna.common.api.APIException;
import crmdna.common.api.APIResponse.Status;
import java.text.SimpleDateFormat;
import java.util.*;
import static crmdna.common.AssertUtils.ensure;
import static crmdna.common.AssertUtils.ensureNotNull;
public class DateUtils {
public static void ensureDateNotInFuture(Month month, int year) {
int currentYear = Calendar.getInstance().get(Calendar.YEAR);
ensure(year != 0, "year is 0");
ensure(year <= currentYear, "year cannot be greater than current year");
ensureNotNull(month, "month is null");
if (year == currentYear) {
int currentMonth = Calendar.getInstance().get(Calendar.MONTH);
ensure(currentMonth >= getZeroBasedMonthIndex(month), "future date not allowed");
}
}
public static Month getMonthEnum(int yyyymmdd) {
ensureFormatYYYYMMDD(yyyymmdd);
int yyyymm = yyyymmdd / 100;
int mm = yyyymm % 100;
switch (mm) {
case 1:
return Month.JAN;
case 2:
return Month.FEB;
case 3:
return Month.MAR;
case 4:
return Month.APR;
case 5:
return Month.MAY;
case 6:
return Month.JUN;
case 7:
return Month.JUL;
case 8:
return Month.AUG;
case 9:
return Month.SEP;
case 10:
return Month.OCT;
case 11:
return Month.NOV;
case 12:
return Month.DEC;
default:
throw new APIException().status(Status.ERROR_RESOURCE_INCORRECT).message(
"Invalid month number [" + mm + "]");
}
}
public static int getZeroBasedMonthIndex(Month month) {
switch (month) {
case JAN:
return 0;
case FEB:
return 1;
case MAR:
return 2;
case APR:
return 3;
case MAY:
return 4;
case JUN:
return 5;
case JUL:
return 6;
case AUG:
return 7;
case SEP:
return 8;
case OCT:
return 9;
case NOV:
return 10;
case DEC:
return 11;
}
throw new APIException().status(Status.ERROR_RESOURCE_INCORRECT).message(
"invalid month [" + month + "]");
}
public static long getMilliSecondsFromDateRange(FutureDateRange dateRange) {
ensureNotNull(dateRange);
final long NUM_MS_PER_DAY = 86400 * 1000;
if (dateRange == FutureDateRange.NEXT_15_DAYS)
return NUM_MS_PER_DAY * 15;
if (dateRange == FutureDateRange.NEXT_30_DAYS)
return NUM_MS_PER_DAY * 30;
if (dateRange == FutureDateRange.NEXT_60_DAYS)
return NUM_MS_PER_DAY * 60;
if (dateRange == FutureDateRange.NEXT_90_DAYS)
return NUM_MS_PER_DAY * 90;
throw new APIException("Cannot get milli seconds from data range [" + dateRange + "]")
.status(Status.ERROR_RESOURCE_INCORRECT);
}
public static long getMilliSecondsFromDateRange(DateRange dateRange) {
ensureNotNull(dateRange);
final long NUM_MS_PER_DAY = 86400 * 1000;
if (dateRange == DateRange.LAST_24_HOURS)
return NUM_MS_PER_DAY;
if (dateRange == DateRange.LAST_48_HOURS)
return NUM_MS_PER_DAY * 2;
if (dateRange == DateRange.LAST_72_HOURS)
return NUM_MS_PER_DAY * 3;
if (dateRange == DateRange.LAST_7_DAYS)
return NUM_MS_PER_DAY * 7;
if (dateRange == DateRange.LAST_15_DAYS)
return NUM_MS_PER_DAY * 15;
if (dateRange == DateRange.LAST_30_DAYS)
return NUM_MS_PER_DAY * 30;
if (dateRange == DateRange.LAST_90_DAYS)
return NUM_MS_PER_DAY * 90;
if (dateRange == DateRange.LAST_180_DAYS)
return NUM_MS_PER_DAY * 180;
if (dateRange == DateRange.LAST_365_DAYS)
return NUM_MS_PER_DAY * 365;
throw new APIException("Cannot get milli seconds from data range [" + dateRange + "]")
.status(Status.ERROR_RESOURCE_INCORRECT);
}
public static int toYYYYMMDD(Date date) {
Calendar calendar = Calendar.getInstance();
calendar.setTime(date);
int year = calendar.get(Calendar.YEAR);
int month = calendar.get(Calendar.MONTH) + 1;
int day = calendar.get(Calendar.DAY_OF_MONTH);
int yyyymmdd = day + month * 100 + year * 10000;
return yyyymmdd;
}
public static Date toDate(int yyyymmdd) {
if (!isFormatInYYYYMMDD(yyyymmdd)) {
Utils.throwIncorrectSpecException("[" + yyyymmdd + "] is not in yyymmdd format");
}
String s = yyyymmdd + "";
int year = Integer.parseInt(s.substring(0, 4));
int month = Integer.parseInt(s.substring(4, 6));
int day = Integer.parseInt(s.substring(6, 8));
Calendar calendar = Calendar.getInstance();
calendar.set(year, month - 1, day);
return calendar.getTime();
}
public static boolean isFormatInYYYYMMDD(int date) {
String s = "" + date;
if (s.length() != 8)
return false;
int year = Integer.parseInt(s.substring(0, 4));
int month = Integer.parseInt(s.substring(4, 6));
int day = Integer.parseInt(s.substring(6, 8));
if ((year < 1970) || (year > 2050))
return false;
if ((month < 1) || (month > 12))
return false;
if ((day < 1) || (day > 31))
return false;
if (month == 2) {
if (day > 29)
return false;
if ((day == 29) && (year % 4 != 0))
return false;
}
if ((month == 4) || (month == 6) || (month == 9) || (month == 11))
if (day == 31)
return false;
return true;
}
public static boolean isFormatInYYYYMM(int date) {
String s = "" + date + "01";
if (s.length() != 8)
return false;
int year = Integer.parseInt(s.substring(0, 4));
int month = Integer.parseInt(s.substring(4, 6));
int day = Integer.parseInt(s.substring(6, 8));
if ((year < 1970) || (year > 2050))
return false;
if ((month < 1) || (month > 12))
return false;
if ((day < 1) || (day > 31))
return false;
if (month == 2) {
if (day > 29)
return false;
if ((day == 29) && (year % 4 != 0))
return false;
}
if ((month == 4) || (month == 6) || (month == 9) || (month == 11))
if (day == 31)
return false;
return true;
}
private static Map<String, String> getMMMtoMMMap() {
Map<String, String> map = new HashMap<>();
map.put("jan", "01");
map.put("feb", "02");
map.put("mar", "03");
map.put("apr", "04");
map.put("may", "05");
map.put("jun", "06");
map.put("jul", "07");
map.put("aug", "08");
map.put("sep", "09");
map.put("oct", "10");
map.put("nov", "11");
map.put("dec", "12");
return map;
}
public static boolean isFormatInMMMYYYY(String s) {
if (s == null)
return false;
s = Utils.removeSpaceUnderscoreBracketAndHyphen(s).toLowerCase();
if (s.length() != 7)
return false;
String mmm = s.substring(0, 3);
String yyyy = s.substring(3, 7);
Map<String, String> mmmTommMap = getMMMtoMMMap();
if (mmmTommMap.containsKey(mmm))
return false;
if (!Utils.canParseAsLong(yyyy))
return false;
return true;
}
public static String toDDMMM(int dateYYYYMMDD) {
ensureFormatYYYYMMDD(dateYYYYMMDD);
String s = "" + dateYYYYMMDD;
int month = Integer.parseInt(s.substring(4, 6));
int day = Integer.parseInt(s.substring(6, 8));
return day + " " + get3CharMonth(month);
}
public static String toYYYYMM(String mmmYYYY) {
ensure(isFormatInMMMYYYY(mmmYYYY), "[" + mmmYYYY + "] is not in format MMMMYYYY");
String mmm = mmmYYYY.substring(0, 3);
String yyyy = mmmYYYY.substring(3, 7);
ensure(mmm.length() == 3);
ensure(yyyy.length() == 4);
Map<String, String> map = getMMMtoMMMap();
ensure(map.containsKey(mmm), "[" + mmm + "] is not a valid value for MMM");
return yyyy + map.get(mmm);
}
public static String get3CharMonth(int month) {
if (1 == month)
return "Jan";
if (2 == month)
return "Feb";
if (3 == month)
return "Mar";
if (4 == month)
return "Apr";
if (5 == month)
return "May";
if (6 == month)
return "Jun";
if (7 == month)
return "Jul";
if (8 == month)
return "Aug";
if (9 == month)
return "Sep";
if (10 == month)
return "Oct";
if (11 == month)
return "Nov";
if (12 == month)
return "Dec";
throw new APIException().status(Status.ERROR_RESOURCE_INCORRECT).message(
"Invalid month [" + month + "]");
}
public static String getDurationAsString(int startYYYYMMDD, int endYYYYMMDD) {
ensureFormatYYYYMMDD(startYYYYMMDD);
ensureFormatYYYYMMDD(endYYYYMMDD);
if (startYYYYMMDD > endYYYYMMDD)
throw new APIException().status(Status.ERROR_RESOURCE_INCORRECT).message(
"Start date should not be greater than end date");
if (startYYYYMMDD == endYYYYMMDD)
return toDDMMMYY(startYYYYMMDD);
String s = "" + startYYYYMMDD;
int yearStart = Integer.parseInt(s.substring(0, 4));
int monthStart = Integer.parseInt(s.substring(4, 6));
int dayStart = Integer.parseInt(s.substring(6, 8));
s = "" + endYYYYMMDD;
int yearEnd = Integer.parseInt(s.substring(0, 4));
int monthEnd = Integer.parseInt(s.substring(4, 6));
if (yearStart == yearEnd) {
if (monthStart == monthEnd) {
return dayStart + " - " + toDDMMMYY(endYYYYMMDD);
}
return toDDMMM(startYYYYMMDD) + " - " + toDDMMMYY(endYYYYMMDD);
}
return toDDMMM(startYYYYMMDD) + " - " + toDDMMMYY(endYYYYMMDD);
}
public static String getDateDiff(long startTimeInSeconds, long endTimeInSeconds) {
long diff = endTimeInSeconds - startTimeInSeconds;
if (diff < 0)
Utils.throwIncorrectSpecException("startTimeInSeconds greater than endTimeInSeconds");
if (diff < 60)
return diff + " seconds";
if (diff < 3600) {
long min = Math.round(diff / 60.0);
return min + " minute(s)";
}
if (diff < 3600 * 24) {
long hours = Math.round(diff / 3600.0);
return hours + " hour(s)";
}
long days = Math.round(diff / 3600.0 / 24.0);
return days + " day(s)";
}
public static String toDDMMMYY(int dateYYYYMMDD) {
ensureFormatYYYYMMDD(dateYYYYMMDD);
String s = "" + dateYYYYMMDD;
int year = Integer.parseInt(s.substring(2, 4));
int month = Integer.parseInt(s.substring(4, 6));
int day = Integer.parseInt(s.substring(6, 8));
return day + " " + get3CharMonth(month) + " " + year;
}
public static void ensureFormatYYYYMMDD(int date) {
boolean valid = isFormatInYYYYMMDD(date);
if (!valid)
throw new APIException("[" + date + "] is not a valid date in YYYYMMDD format.")
.status(Status.ERROR_RESOURCE_INCORRECT);
}
public static long getNanoSeconds(Date timestamp) {
// returns time in nano seconds
// system clocks are only accurate up to millisecond precision
// get the time in ms and add a random no between 0 and 1 million to
// convert into nanoseconds
return timestamp.getTime() * 1000000 + new Random().nextInt(999999);
}
public static long getMicroSeconds(Date timestamp) {
// returns time in nano seconds
// system clocks are only accurate up to millisecond precision
// get the time in ms and add a random no between 0 and 1 million to
// convert into nanoseconds
return timestamp.getTime() * 1000 + new Random().nextInt(999);
}
public static String toISOString(Date timestamp) {
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd'T'HH:mmZ");
sdf.setTimeZone(TimeZone.getTimeZone("UTC"));
return sdf.format(timestamp);
}
public enum Month {
JAN, FEB, MAR, APR, MAY, JUN, JUL, AUG, SEP, OCT, NOV, DEC
}
public enum DateRange {
LAST_24_HOURS, LAST_48_HOURS, LAST_72_HOURS, LAST_7_DAYS, LAST_15_DAYS, LAST_30_DAYS, LAST_90_DAYS, LAST_180_DAYS, LAST_365_DAYS
}
public enum FutureDateRange {
NEXT_15_DAYS, NEXT_30_DAYS, NEXT_60_DAYS, NEXT_90_DAYS
}
}