/*
* 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.
*
* Other licenses:
* -----------------------------------------------------------------------------
* Commercial licenses for this work are available. These replace the above
* ASL 2.0 and offer limited warranties, support, maintenance, and commercial
* database integrations.
*
* For more information, please visit: http://www.jooq.org/licenses
*
*
*
*
*
*
*
*
*
*
*
*
*
*/
package org.jooq.types;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.jooq.Field;
import org.jooq.SQLDialect;
/**
* An implementation for the SQL standard <code>INTERVAL YEAR TO MONTH</code>
* data type.
* <p>
* <code>YearToMonth</code> is a {@link Number} whose {@link Number#intValue()}
* represents the number of months of the interval.
* <p>
* Note: only a few databases actually support this data type on its own. You
* can still use it for date time arithmetic in other databases, though, through
* {@link Field#add(Field)} and {@link Field#sub(Field)} Databases that have
* been observed to natively support <code>INTERVAL</code> data types are:
* <ul>
* <li> {@link SQLDialect#HSQLDB}</li>
* <li> {@link SQLDialect#INGRES}</li>
* <li> {@link SQLDialect#ORACLE}</li>
* <li> {@link SQLDialect#POSTGRES}</li>
* </ul>
* <p>
* These dialects have been observed to partially support <code>INTERVAL</code>
* data types in date time arithmetic functions, such as
* <code>TIMESTAMPADD</code>, and <code>TIMESTAMPDIFF</code>:
* <ul>
* <li> {@link SQLDialect#CUBRID}</li>
* <li> {@link SQLDialect#MARIADB}</li>
* <li> {@link SQLDialect#MYSQL}</li>
* </ul>
*
* @author Lukas Eder
* @see Interval
*/
public final class YearToMonth extends Number implements Interval, Comparable<YearToMonth> {
/**
* Generated UID
*/
private static final long serialVersionUID = 1308553645456594273L;
private static final Pattern PATTERN = Pattern.compile("(\\+|-)?(\\d+)-(\\d+)");
private final boolean negative;
private final int years;
private final int months;
/**
* Create a new year-month interval.
*/
public YearToMonth(int years) {
this(years, 0, false);
}
/**
* Create a new year-month interval.
*/
public YearToMonth(int years, int months) {
this(years, months, false);
}
private YearToMonth(int years, int months, boolean negative) {
// Perform normalisation. Specifically, Postgres may return intervals
// such as 0-13
if (months >= 12) {
years += (months / 12);
months %= 12;
}
this.negative = negative;
this.years = years;
this.months = months;
}
/**
* Parse a string representation of a <code>INTERVAL YEAR TO MONTH</code>
*
* @param string A string representation of the form
* <code>[+|-][years]-[months]</code>
* @return The parsed <code>YEAR TO MONTH</code> object, or
* <code>null</code> if the string could not be parsed.
*/
public static YearToMonth valueOf(String string) {
if (string != null) {
Matcher matcher = PATTERN.matcher(string);
if (matcher.find()) {
boolean negative = "-".equals(matcher.group(1));
int years = Integer.parseInt(matcher.group(2));
int months = Integer.parseInt(matcher.group(3));
return new YearToMonth(years, months, negative);
}
}
return null;
}
// -------------------------------------------------------------------------
// XXX Interval API
// -------------------------------------------------------------------------
@Override
public final YearToMonth neg() {
return new YearToMonth(years, months, !negative);
}
@Override
public final YearToMonth abs() {
return new YearToMonth(years, months, false);
}
public final int getYears() {
return years;
}
public final int getMonths() {
return months;
}
@Override
public final int getSign() {
return negative ? -1 : 1;
}
// -------------------------------------------------------------------------
// XXX Number API
// -------------------------------------------------------------------------
@Override
public final int intValue() {
return (negative ? -1 : 1) * (12 * years + months);
}
@Override
public final long longValue() {
return intValue();
}
@Override
public final float floatValue() {
return intValue();
}
@Override
public final double doubleValue() {
return intValue();
}
// -------------------------------------------------------------------------
// XXX Comparable and Object API
// -------------------------------------------------------------------------
@Override
public final int compareTo(YearToMonth that) {
if (years < that.years) {
return -1;
}
if (years > that.years) {
return 1;
}
if (months < that.months) {
return -1;
}
if (months > that.months) {
return 1;
}
return 0;
}
@Override
public final int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + months;
result = prime * result + years;
return result;
}
@Override
public final boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
YearToMonth other = (YearToMonth) obj;
if (months != other.months)
return false;
if (years != other.years)
return false;
return true;
}
@Override
public final String toString() {
StringBuilder sb = new StringBuilder();
sb.append(negative ? "-" : "+");
sb.append(years);
sb.append("-");
sb.append(months);
return sb.toString();
}
}