/*
* Copyright 2015 herd contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.finra.herd.core;
import java.sql.Timestamp;
import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;
import javax.xml.datatype.DatatypeConfigurationException;
import javax.xml.datatype.DatatypeFactory;
import javax.xml.datatype.XMLGregorianCalendar;
import org.apache.commons.lang3.time.DateUtils;
/**
* Provides additional utility methods for dates and times.
*/
public class HerdDateUtils extends DateUtils
{
/**
* Returns a calendar for the current day that does not have the time set.
*
* @return the current date.
*/
public static Calendar getCurrentCalendarNoTime()
{
// Get the current year, month, and day before we clear out the fields.
Calendar calendar = Calendar.getInstance();
int year = calendar.get(Calendar.YEAR);
int month = calendar.get(Calendar.MONTH);
int day = calendar.get(Calendar.DATE);
// Clear out ALL the fields of the calendar. If any are not cleared, we run the risk of something being set that we don't want.
calendar.clear();
// Update the calendar with just the year, month, and day.
calendar.set(year, month, day);
// Return the updated calendar.
return calendar;
}
/**
* Formats a "total milliseconds" duration.
*
* @param duration the duration in milliseconds to format.
*
* @return The formatted duration.
*/
public static String formatDuration(long duration)
{
// Initialize the result string.
StringBuilder result = new StringBuilder();
// Since we have to display the readable duration, append it initially.
long remainingDuration = duration;
// If the duration is 0, then just return 0 milliseconds.
if (remainingDuration == 0)
{
result.append("0 Milliseconds");
}
else
{
// Compute each duration separately.
remainingDuration = processDuration(remainingDuration, MILLIS_PER_DAY, "Day", result, false);
remainingDuration = processDuration(remainingDuration, MILLIS_PER_HOUR, "Hour", result, false);
remainingDuration = processDuration(remainingDuration, MILLIS_PER_MINUTE, "Minute", result, false);
remainingDuration = processDuration(remainingDuration, MILLIS_PER_SECOND, "Second", result, false);
// Compute the milliseconds.
long milliSeconds = remainingDuration;
if (milliSeconds > 0)
{
// Just display the final millisecond portion no matter what (i.e. the duration is 1).
processDuration(remainingDuration, 1, "Millisecond", result, true);
}
}
// Return the result.
return result.toString();
}
/**
* Process a single duration.
*
* @param remainingDuration the remaining duration in milliseconds.
* @param millisPerDuration the number of milliseconds per one duration (e.g. 1000 milliseconds in a single second).
* @param durationName the duration name (e.g. "Day").
* @param result the result string.
* @param displayZeroDuration Flag that indicates whether a "0" duration should be displayed or not.
*
* @return the new remaining duration in milliseconds after the current duration is substracted from the original remaining duration.
*/
private static long processDuration(long remainingDuration, long millisPerDuration, String durationName, StringBuilder result, boolean displayZeroDuration)
{
// Compute how many durations (e.g. "5" days).
long duration = remainingDuration / millisPerDuration;
// Compute the new remaining duration which is the previous remaining duration - the new duration in milliseconds.
long newRemainingDuration = remainingDuration - (duration * millisPerDuration);
// Only append the duration to the result if some time exists in the duration (e.g. we don't add "0 Days").
if (duration > 0 || displayZeroDuration)
{
// If the result previously had a value, add a comma to separate this duration from the previous durations (e.g. 5 days"," ...).
if (result.length() > 0)
{
result.append(", ");
}
// Append the duration along with the duration name (e.g. "5 day").
result.append(String.valueOf(duration)).append(' ').append(durationName);
// If the duration is not 1, then make it plural (e.g. 5 day"s").
if (duration != 1)
{
result.append('s');
}
}
// Return the new remaining duration so the calculation can continue.
return newRemainingDuration;
}
/**
* Gets the current date/time as an XMLGregorianCalendar with the default time zone in the default locale.
*
* @return the current date/time.
*/
public static XMLGregorianCalendar now()
{
return getXMLGregorianCalendarValue(null);
}
/**
* Gets an instance of XMLGregorianCalendar class initialized per the specified java.util.Date value. Returns the current date/time if date is null.
*
* @param date the java.util.Date value to be converted into XMLGregorianCalendar.
*
* @return the XMLGregorianCalendar instance initialized per specified date value
*/
public static XMLGregorianCalendar getXMLGregorianCalendarValue(Date date)
{
GregorianCalendar gregorianCalendar = new GregorianCalendar();
if (date != null)
{
gregorianCalendar.setTime(date);
}
try
{
return DatatypeFactory.newInstance().newXMLGregorianCalendar(gregorianCalendar);
}
catch (DatatypeConfigurationException ex)
{
throw new IllegalStateException("Failed to create a new instance of DataTypeFactory.", ex);
}
}
/**
* Adds a number of days to a timestamp returning a new object. The original {@code Timestamp} is unchanged.
*
* @param timestamp the timestamp, not null
* @param amount the amount to add, may be negative
*
* @return the new {@code Timestamp} with the amount added
*/
public static Timestamp addDays(Timestamp timestamp, int amount)
{
Calendar calendar = Calendar.getInstance();
calendar.setTimeInMillis(timestamp.getTime());
return new Timestamp(addDays(calendar.getTime(), amount).getTime());
}
/**
* Adds a number of minutes to a timestamp returning a new object. The original {@code Timestamp} is unchanged.
*
* @param timestamp the timestamp, not null
* @param amount the amount to add, may be negative
*
* @return the new {@code Timestamp} with the amount added
*/
public static Timestamp addMinutes(Timestamp timestamp, int amount)
{
Calendar calendar = Calendar.getInstance();
calendar.setTimeInMillis(timestamp.getTime());
return new Timestamp(addMinutes(calendar.getTime(), amount).getTime());
}
}