DurationImpl.java
/*
* Copyright 2015 gregorygraham.
*
* 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 nz.co.gregs.dbvolution.internal.datatypes;
import java.time.Duration;
import java.time.Instant;
import java.time.LocalDateTime;
import java.time.ZoneOffset;
import nz.co.gregs.regexi.Regex;
import nz.co.gregs.regexi.RegexSplitter;
import nz.co.gregs.regexi.RegexValueFinder;
/**
*
*
* @author gregorygraham
*/
public class DurationImpl {
private static final String ZERO_DURATION_STRING = "P0DT0H0M0.0S";
private static final String DAYS_CAPTURE = "days";
private static final String HOURS_CAPTURE = "hours";
private static final String MINUTES_CAPTURE = "minutes";
private static final String SECONDS_CAPTURE = "seconds";
private static final Regex REGEX = Regex.empty()
.literal("P").beginNamedCapture(DAYS_CAPTURE).numberLike().endNamedCapture()
.literal("DT").beginNamedCapture(HOURS_CAPTURE).numberLike().endNamedCapture()
.literal("H").beginNamedCapture(MINUTES_CAPTURE).numberLike().endNamedCapture()
.literal("M").beginNamedCapture(SECONDS_CAPTURE).numberLike().endNamedCapture()
.literal("S").toRegex();
private static final RegexValueFinder GET_DAYS = REGEX.returnValueFrom(DAYS_CAPTURE);
private static final RegexValueFinder GET_HOURS = REGEX.returnValueFrom(HOURS_CAPTURE);
private static final RegexValueFinder GET_MINUTES = REGEX.returnValueFrom(MINUTES_CAPTURE);
private static final RegexValueFinder GET_SECONDS = REGEX.returnValueFrom(SECONDS_CAPTURE);
/**
* Default constructor
*
*/
public DurationImpl() {
}
/**
*
*
* @return the DateRepeat version of Zero
*/
public static String getZeroDurationString() {
return ZERO_DURATION_STRING;
}
/**
*
* @param original the first date
* @param compareTo the second date
*
* @return the DateRepeat the represents the difference between these 2 dates
*/
@SuppressWarnings("deprecation")
public static String repeatFromTwoDates(LocalDateTime original, LocalDateTime compareTo) {
if (original == null || compareTo == null) {
return null;
}
final Instant originalInstant = original.toInstant(ZoneOffset.UTC);
double originalTime = 0.0d + originalInstant.getEpochSecond() + ((0.0d + originalInstant.getNano()) / 1000000000.0d);
final Instant compareInstant = compareTo.toInstant(ZoneOffset.UTC);
double compareTime = 0.0d + compareInstant.getEpochSecond() + ((0.0d + compareInstant.getNano()) / 1000000000.0d);
double differenceInSeconds = originalTime - compareTime;
int days = (int) (differenceInSeconds / (SECONDS_IN_A_DAY));
differenceInSeconds -= days * SECONDS_IN_A_DAY;
int hours = (int) (differenceInSeconds / (SECONDS_IN_AN_HOUR));
differenceInSeconds -= hours * SECONDS_IN_AN_HOUR;
int minutes = (int) (differenceInSeconds / (SECONDS_IN_A_MINUTE));
differenceInSeconds -= minutes * SECONDS_IN_A_MINUTE;
int seconds = (int) (differenceInSeconds);
String intervalString = "P" + days + "DT" + hours + "H" + minutes + "M" + seconds + "S";
return intervalString;
}
private static final int SECONDS_IN_A_MINUTE = 60;
private static final int SECONDS_IN_AN_HOUR = 60 * 60;
private static final int SECONDS_IN_A_DAY = 24 * 60 * 60;
/**
*
* @param interval the Duration to convert to DBDuration's string format
* @return the DBDuration equivalent of the Duration value
*/
public static String getDurationString(Duration interval) {
if (interval == null) {
return null;
}
int days = (int) interval.toDaysPart();
int hours = interval.toHoursPart();
int minutes = interval.toMinutesPart();
int nanos = interval.toNanosPart();
double seconds = interval.toSecondsPart() + (nanos / 1000000000.0);
String intervalString = "P" + days + "DT" + hours + "H" + minutes + "M" + seconds + "S";
return intervalString;
}
/**
*
* @param original the first date
* @param compareTo the second date
*
* @return TRUE if the DateRepeats are the same, otherwise FALSE
*/
public static boolean isEqualTo(String original, String compareTo) {
return compareDurationStrings(original, compareTo) == 0;
}
/**
*
* @param original the first date
* @param compareTo the second date
*
* @return TRUE if the first DateRepeat value is greater than the second,
* otherwise FALSE
*/
public static boolean isGreaterThan(String original, String compareTo) {
return compareDurationStrings(original, compareTo) == 1;
}
/**
*
* @param original the first date
* @param compareTo the second date
*
* @return TRUE if the first DateRepeat value is less than the second,
* otherwise FALSE
*/
public static boolean isLessThan(String original, String compareTo) {
return compareDurationStrings(original, compareTo) == -1;
}
private static final RegexSplitter SPLIT_ON_LETTERS = Regex.empty().beginSetIncluding().includeLetters().endSet().toSplitter();
/**
*
* @param original the first date
* @param compareTo the second date
*
* @return -1 if the first DateRepeat is the smallest, 0 if they are equal,
* and 1 if the first is the largest.
*/
public static Integer compareDurationStrings(String original, String compareTo) {
if (original == null || compareTo == null) {
return null;
}
String[] splitOriginal = SPLIT_ON_LETTERS.split(original);
String[] splitCompareTo = SPLIT_ON_LETTERS.split(compareTo);
for (int i = 1; i < splitCompareTo.length; i++) { // Start at 1 because the first split is empty
double intOriginal = Double.parseDouble(splitOriginal[i]);
double intCompareTo = Double.parseDouble(splitCompareTo[i]);
if (intOriginal > intCompareTo) {
return 1;
}
if (intOriginal < intCompareTo) {
return -1;
}
}
return 0;
}
/**
*
* @param original the first date.
* @param intervalStr the DateRepeat to offset the date.
*
* @return the Date value offset by the DateRepeat value.
*/
public static LocalDateTime addDateAndDurationString(LocalDateTime original, String intervalStr) {
if (original == null || intervalStr == null || intervalStr.length() == 0 || original.toString().length() == 0) {
return null;
}
int days = getDayPart(intervalStr);
int hours = getHourPart(intervalStr);
int minutes = getMinutePart(intervalStr);
int seconds = getSecondPart(intervalStr);
int nanos = getNanoPart(intervalStr);
LocalDateTime cal = LocalDateTime.from(original);
cal.plusDays(days);
cal.plusHours(hours);
cal.plusMinutes(minutes);
cal.plusSeconds(seconds);
cal.plusNanos(nanos);
return cal;
}
/**
*
* @param original the first date.
* @param intervalInput the DateRepeat to offset the date.
*
* @return the Date shift backwards (towards the past) by the DateRepeat
* value.
*/
public static LocalDateTime subtractDateAndDurationString(LocalDateTime original, String intervalInput) {
if (original == null || intervalInput == null || intervalInput.length() == 0) {
return null;
}
int days = getDayPart(intervalInput);
int hours = getHourPart(intervalInput);
int minutes = getMinutePart(intervalInput);
int seconds = getSecondPart(intervalInput);
int nanos = getNanoPart(intervalInput);
LocalDateTime cal = LocalDateTime.from(original);
cal.minusDays(days);
cal.minusHours(hours);
cal.minusMinutes(minutes);
cal.minusSeconds(seconds);
cal.minusNanos(nanos);
return cal;
}
/**
*
* @param intervalStr the DateRepeat to parse
*
* @return the DateRepeat value represented by the String value
*/
public static Duration parseDateRepeatFromGetString(String intervalStr) {
if (intervalStr == null || intervalStr.length() == 0) {
return null;
}
Duration interval = Duration.parse(intervalStr);
return interval;
}
/**
*
* @param intervalStr the DateRepeat
*
* @return get the fractional seconds to millisecond precision
* @throws NumberFormatException it's possible that the numbers are malformed
*/
public static Integer getNanoPart(String intervalStr) throws NumberFormatException {
if (intervalStr == null || intervalStr.length() == 0) {
return null;
}
final String stringValue = GET_SECONDS.getValueFrom(intervalStr).orElse("");
if (stringValue.isEmpty()) {
return null;
}
final Double secondsDouble = Double.parseDouble(stringValue);
final int secondsInt = secondsDouble.intValue();
final Double nanoDouble = secondsDouble * 1000000000.0 - secondsInt * 1000000000;
final int nanos = nanoDouble.intValue();
return nanos;
}
/**
*
* @param intervalStr the DateRepeat
*
* @return get the integer and fractional seconds part of the DateRepeat
* @throws NumberFormatException it's possible that the numbers are malformed
*/
public static Integer getSecondPart(String intervalStr) throws NumberFormatException {
if (intervalStr == null || intervalStr.length() == 0 || !REGEX.matchesEntireString(intervalStr)) {
return null;
}
final String stringValue = GET_SECONDS.getValueFrom(intervalStr).orElse("");
if (stringValue.isEmpty()) {
return null;
}
final Double valueOf = Double.valueOf(stringValue);
return valueOf.intValue();
}
/**
*
* @param intervalStr the DateRepeat
*
* @return get the minutes part of the DateRepeat
* @throws NumberFormatException it's possible that the numbers are malformed
*/
public static Integer getMinutePart(String intervalStr) throws NumberFormatException {
if (intervalStr == null || intervalStr.length() == 0 || !REGEX.matchesEntireString(intervalStr)) {
return null;
}
final String stringValue = GET_MINUTES.getValueFrom(intervalStr).orElse("");
if (stringValue.isEmpty()) {
return null;
}
return Integer.parseInt(stringValue);
}
/**
*
* @param intervalStr the DateRepeat
*
* @return get the hour part of the DateRepeat value
* @throws NumberFormatException it's possible that the numbers are malformed
*/
public static Integer getHourPart(String intervalStr) throws NumberFormatException {
if (intervalStr == null || intervalStr.length() == 0 || !REGEX.matchesEntireString(intervalStr)) {
return null;
}
final String stringValue = GET_HOURS.getValueFrom(intervalStr).orElse("");
if (stringValue.isEmpty()) {
return null;
}
return Integer.parseInt(stringValue);
}
/**
*
* @param intervalStr the DateRepeat
*
* @return get the day part of the DateRepeat value
* @throws NumberFormatException it's possible that the numbers are malformed
*/
public static Integer getDayPart(String intervalStr) throws NumberFormatException {
if (intervalStr == null || intervalStr.length() == 0 || !REGEX.matchesEntireString(intervalStr)) {
return null;
}
final String stringValue = GET_DAYS.getValueFrom(intervalStr).orElse("");
if (stringValue.isEmpty()) {
return null;
}
return Integer.parseInt(stringValue);
}
}