package org.h2.expression.function;
import static org.h2.expression.function.Function.CENTURY;
import static org.h2.expression.function.Function.DAY_OF_MONTH;
import static org.h2.expression.function.Function.DAY_OF_WEEK;
import static org.h2.expression.function.Function.DAY_OF_YEAR;
import static org.h2.expression.function.Function.DECADE;
import static org.h2.expression.function.Function.DOW;
import static org.h2.expression.function.Function.EPOCH;
import static org.h2.expression.function.Function.HOUR;
import static org.h2.expression.function.Function.ISO_DAY_OF_WEEK;
import static org.h2.expression.function.Function.ISO_WEEK;
import static org.h2.expression.function.Function.ISO_YEAR;
import static org.h2.expression.function.Function.MICROSECOND;
import static org.h2.expression.function.Function.MILLENNIUM;
import static org.h2.expression.function.Function.MILLISECOND;
import static org.h2.expression.function.Function.MINUTE;
import static org.h2.expression.function.Function.MONTH;
import static org.h2.expression.function.Function.NANOSECOND;
import static org.h2.expression.function.Function.QUARTER;
import static org.h2.expression.function.Function.SECOND;
import static org.h2.expression.function.Function.TIMEZONE_HOUR;
import static org.h2.expression.function.Function.TIMEZONE_MINUTE;
import static org.h2.expression.function.Function.WEEK;
import static org.h2.expression.function.Function.YEAR;
import static org.h2.util.DateTimeUtils.MILLIS_PER_DAY;
import static org.h2.util.DateTimeUtils.NANOS_PER_DAY;
import static org.h2.util.DateTimeUtils.NANOS_PER_HOUR;
import static org.h2.util.DateTimeUtils.NANOS_PER_MINUTE;
import static org.h2.util.DateTimeUtils.NANOS_PER_SECOND;
import java.math.BigDecimal;
import java.text.DateFormatSymbols;
import java.text.SimpleDateFormat;
import java.util.GregorianCalendar;
import java.util.HashMap;
import java.util.Locale;
import java.util.TimeZone;
import org.h2.api.ErrorCode;
import org.h2.api.IntervalQualifier;
import org.h2.engine.Mode;
import org.h2.engine.Mode.ModeEnum;
import org.h2.message.DbException;
import org.h2.util.DateTimeUtils;
import org.h2.util.IntervalUtils;
import org.h2.util.StringUtils;
import org.h2.value.Value;
import org.h2.value.ValueDate;
import org.h2.value.ValueDecimal;
import org.h2.value.ValueInt;
import org.h2.value.ValueInterval;
import org.h2.value.ValueTime;
import org.h2.value.ValueTimestamp;
import org.h2.value.ValueTimestampTimeZone;
public final class DateTimeFunctions {
private static final HashMap<String, Integer> DATE_PART = new HashMap<>(128);
private static volatile String[][] MONTHS_AND_WEEKS;
static {
DATE_PART.put("SQL_TSI_YEAR", YEAR);
DATE_PART.put("YEAR", YEAR);
DATE_PART.put("YYYY", YEAR);
DATE_PART.put("YY", YEAR);
DATE_PART.put("ISO_YEAR", ISO_YEAR);
DATE_PART.put("ISOYEAR", ISO_YEAR);
DATE_PART.put("SQL_TSI_MONTH", MONTH);
DATE_PART.put("MONTH", MONTH);
DATE_PART.put("MM", MONTH);
DATE_PART.put("M", MONTH);
DATE_PART.put("QUARTER", QUARTER);
DATE_PART.put("SQL_TSI_WEEK", WEEK);
DATE_PART.put("WW", WEEK);
DATE_PART.put("WK", WEEK);
DATE_PART.put("WEEK", WEEK);
DATE_PART.put("ISO_WEEK", ISO_WEEK);
DATE_PART.put("DAY", DAY_OF_MONTH);
DATE_PART.put("DD", DAY_OF_MONTH);
DATE_PART.put("D", DAY_OF_MONTH);
DATE_PART.put("SQL_TSI_DAY", DAY_OF_MONTH);
DATE_PART.put("DAY_OF_WEEK", DAY_OF_WEEK);
DATE_PART.put("DAYOFWEEK", DAY_OF_WEEK);
DATE_PART.put("DOW", DOW);
DATE_PART.put("ISO_DAY_OF_WEEK", ISO_DAY_OF_WEEK);
DATE_PART.put("ISODOW", ISO_DAY_OF_WEEK);
DATE_PART.put("DAYOFYEAR", DAY_OF_YEAR);
DATE_PART.put("DAY_OF_YEAR", DAY_OF_YEAR);
DATE_PART.put("DY", DAY_OF_YEAR);
DATE_PART.put("DOY", DAY_OF_YEAR);
DATE_PART.put("SQL_TSI_HOUR", HOUR);
DATE_PART.put("HOUR", HOUR);
DATE_PART.put("HH", HOUR);
DATE_PART.put("SQL_TSI_MINUTE", MINUTE);
DATE_PART.put("MINUTE", MINUTE);
DATE_PART.put("MI", MINUTE);
DATE_PART.put("N", MINUTE);
DATE_PART.put("SQL_TSI_SECOND", SECOND);
DATE_PART.put("SECOND", SECOND);
DATE_PART.put("SS", SECOND);
DATE_PART.put("S", SECOND);
DATE_PART.put("MILLISECOND", MILLISECOND);
DATE_PART.put("MILLISECONDS", MILLISECOND);
DATE_PART.put("MS", MILLISECOND);
DATE_PART.put("EPOCH", EPOCH);
DATE_PART.put("MICROSECOND", MICROSECOND);
DATE_PART.put("MICROSECONDS", MICROSECOND);
DATE_PART.put("MCS", MICROSECOND);
DATE_PART.put("NANOSECOND", NANOSECOND);
DATE_PART.put("NS", NANOSECOND);
DATE_PART.put("TIMEZONE_HOUR", TIMEZONE_HOUR);
DATE_PART.put("TIMEZONE_MINUTE", TIMEZONE_MINUTE);
DATE_PART.put("DECADE", DECADE);
DATE_PART.put("CENTURY", CENTURY);
DATE_PART.put("MILLENNIUM", MILLENNIUM);
}
public static Value dateadd(String part, long count, Value v) {
int field = getDatePart(part);
if (field != MILLISECOND && field != MICROSECOND && field != NANOSECOND
&& (count > Integer.MAX_VALUE || count < Integer.MIN_VALUE)) {
throw DbException.getInvalidValueException("DATEADD count", count);
}
boolean withDate = !(v instanceof ValueTime);
boolean withTime = !(v instanceof ValueDate);
boolean forceTimestamp = false;
long[] a = DateTimeUtils.dateAndTimeFromValue(v);
long dateValue = a[0];
long timeNanos = a[1];
switch (field) {
case QUARTER:
count *= 3;
case YEAR:
case MONTH: {
if (!withDate) {
throw DbException.getInvalidValueException("DATEADD time part", part);
}
long year = DateTimeUtils.yearFromDateValue(dateValue);
long month = DateTimeUtils.monthFromDateValue(dateValue);
int day = DateTimeUtils.dayFromDateValue(dateValue);
if (field == YEAR) {
year += count;
} else {
month += count;
}
dateValue = DateTimeUtils.dateValueFromDenormalizedDate(year, month, day);
return DateTimeUtils.dateTimeToValue(v, dateValue, timeNanos, forceTimestamp);
}
case WEEK:
case ISO_WEEK:
count *= 7;
case DAY_OF_WEEK:
case DOW:
case ISO_DAY_OF_WEEK:
case DAY_OF_MONTH:
case DAY_OF_YEAR:
if (!withDate) {
throw DbException.getInvalidValueException("DATEADD time part", part);
}
dateValue = DateTimeUtils
.dateValueFromAbsoluteDay(DateTimeUtils.absoluteDayFromDateValue(dateValue) + count);
return DateTimeUtils.dateTimeToValue(v, dateValue, timeNanos, forceTimestamp);
case HOUR:
count *= NANOS_PER_HOUR;
break;
case MINUTE:
count *= NANOS_PER_MINUTE;
break;
case SECOND:
case EPOCH:
count *= NANOS_PER_SECOND;
break;
case MILLISECOND:
count *= 1_000_000;
break;
case MICROSECOND:
count *= 1_000;
break;
case NANOSECOND:
break;
case TIMEZONE_HOUR:
count *= 60;
case TIMEZONE_MINUTE: {
if (!(v instanceof ValueTimestampTimeZone)) {
throw DbException.getUnsupportedException("DATEADD " + part);
}
count += ((ValueTimestampTimeZone) v).getTimeZoneOffsetMins();
return ValueTimestampTimeZone.fromDateValueAndNanos(dateValue, timeNanos, (short) count);
}
default:
throw DbException.getUnsupportedException("DATEADD " + part);
}
if (!withTime) {
forceTimestamp = true;
}
timeNanos += count;
if (timeNanos >= NANOS_PER_DAY || timeNanos < 0) {
long d;
if (timeNanos >= NANOS_PER_DAY) {
d = timeNanos / NANOS_PER_DAY;
} else {
d = (timeNanos - NANOS_PER_DAY + 1) / NANOS_PER_DAY;
}
timeNanos -= d * NANOS_PER_DAY;
return DateTimeUtils.dateTimeToValue(v,
DateTimeUtils.dateValueFromAbsoluteDay(DateTimeUtils.absoluteDayFromDateValue(dateValue) + d),
timeNanos, forceTimestamp);
}
return DateTimeUtils.dateTimeToValue(v, dateValue, timeNanos, forceTimestamp);
}
public static long datediff(String part, Value v1, Value v2) {
int field = getDatePart(part);
long[] a1 = DateTimeUtils.dateAndTimeFromValue(v1);
long dateValue1 = a1[0];
long absolute1 = DateTimeUtils.absoluteDayFromDateValue(dateValue1);
long[] a2 = DateTimeUtils.dateAndTimeFromValue(v2);
long dateValue2 = a2[0];
long absolute2 = DateTimeUtils.absoluteDayFromDateValue(dateValue2);
switch (field) {
case NANOSECOND:
case MICROSECOND:
case MILLISECOND:
case SECOND:
case EPOCH:
case MINUTE:
case HOUR:
long timeNanos1 = a1[1];
long timeNanos2 = a2[1];
switch (field) {
case NANOSECOND:
return (absolute2 - absolute1) * NANOS_PER_DAY + (timeNanos2 - timeNanos1);
case MICROSECOND:
return (absolute2 - absolute1) * (MILLIS_PER_DAY * 1_000)
+ (timeNanos2 / 1_000 - timeNanos1 / 1_000);
case MILLISECOND:
return (absolute2 - absolute1) * MILLIS_PER_DAY
+ (timeNanos2 / 1_000_000 - timeNanos1 / 1_000_000);
case SECOND:
case EPOCH:
return (absolute2 - absolute1) * 86_400
+ (timeNanos2 / NANOS_PER_SECOND - timeNanos1 / NANOS_PER_SECOND);
case MINUTE:
return (absolute2 - absolute1) * 1_440
+ (timeNanos2 / NANOS_PER_MINUTE - timeNanos1 / NANOS_PER_MINUTE);
case HOUR:
return (absolute2 - absolute1) * 24 + (timeNanos2 / NANOS_PER_HOUR - timeNanos1 / NANOS_PER_HOUR);
}
case DAY_OF_MONTH:
case DAY_OF_YEAR:
case DAY_OF_WEEK:
case DOW:
case ISO_DAY_OF_WEEK:
return absolute2 - absolute1;
case WEEK:
return weekdiff(absolute1, absolute2, 0);
case ISO_WEEK:
return weekdiff(absolute1, absolute2, 1);
case MONTH:
return (DateTimeUtils.yearFromDateValue(dateValue2) - DateTimeUtils.yearFromDateValue(dateValue1)) * 12
+ DateTimeUtils.monthFromDateValue(dateValue2) - DateTimeUtils.monthFromDateValue(dateValue1);
case QUARTER:
return (DateTimeUtils.yearFromDateValue(dateValue2) - DateTimeUtils.yearFromDateValue(dateValue1)) * 4
+ (DateTimeUtils.monthFromDateValue(dateValue2) - 1) / 3
- (DateTimeUtils.monthFromDateValue(dateValue1) - 1) / 3;
case YEAR:
return DateTimeUtils.yearFromDateValue(dateValue2) - DateTimeUtils.yearFromDateValue(dateValue1);
case TIMEZONE_HOUR:
case TIMEZONE_MINUTE: {
int offsetMinutes1;
if (v1 instanceof ValueTimestampTimeZone) {
offsetMinutes1 = ((ValueTimestampTimeZone) v1).getTimeZoneOffsetMins();
} else {
offsetMinutes1 = DateTimeUtils.getTimeZoneOffsetMillis(null, dateValue1, a1[1]);
}
int offsetMinutes2;
if (v2 instanceof ValueTimestampTimeZone) {
offsetMinutes2 = ((ValueTimestampTimeZone) v2).getTimeZoneOffsetMins();
} else {
offsetMinutes2 = DateTimeUtils.getTimeZoneOffsetMillis(null, dateValue2, a2[1]);
}
if (field == TIMEZONE_HOUR) {
return (offsetMinutes2 / 60) - (offsetMinutes1 / 60);
} else {
return offsetMinutes2 - offsetMinutes1;
}
}
default:
throw DbException.getUnsupportedException("DATEDIFF " + part);
}
}
public static Value (String part, Value value, Mode mode) {
Value result;
int field = getDatePart(part);
if (field != EPOCH) {
result = ValueInt.get(getIntDatePart(value, field, mode));
} else {
if (value instanceof ValueInterval) {
ValueInterval interval = (ValueInterval) value;
BigDecimal bd;
if (interval.getQualifier().isYearMonth()) {
interval = (ValueInterval) interval.convertTo(Value.INTERVAL_YEAR_TO_MONTH);
long leading = interval.getLeading();
long remaining = interval.getRemaining();
bd = BigDecimal.valueOf(leading).multiply(BigDecimal.valueOf(31557600))
.add(BigDecimal.valueOf(remaining * 2592000));
if (interval.isNegative()) {
bd = bd.negate();
}
} else {
bd = new BigDecimal(IntervalUtils.intervalToAbsolute(interval))
.divide(BigDecimal.valueOf(NANOS_PER_SECOND));
}
return ValueDecimal.get(bd);
}
long[] a = DateTimeUtils.dateAndTimeFromValue(value);
long dateValue = a[0];
long timeNanos = a[1];
BigDecimal timeNanosBigDecimal = new BigDecimal(timeNanos);
BigDecimal numberOfDays = new BigDecimal(DateTimeUtils.absoluteDayFromDateValue(dateValue));
BigDecimal nanosSeconds = new BigDecimal(NANOS_PER_SECOND);
BigDecimal secondsPerDay = new BigDecimal(DateTimeUtils.SECONDS_PER_DAY);
if (value instanceof ValueTime) {
result = ValueDecimal.get(timeNanosBigDecimal.divide(nanosSeconds));
} else if (value instanceof ValueDate) {
result = ValueDecimal.get(numberOfDays.multiply(secondsPerDay));
} else if (value instanceof ValueTimestampTimeZone) {
ValueTimestampTimeZone v = (ValueTimestampTimeZone) value;
BigDecimal timeZoneOffsetSeconds = new BigDecimal(v.getTimeZoneOffsetMins() * 60);
result = ValueDecimal.get(timeNanosBigDecimal.divide(nanosSeconds)
.add(numberOfDays.multiply(secondsPerDay)).subtract(timeZoneOffsetSeconds));
} else {
result = ValueDecimal
.get(timeNanosBigDecimal.divide(nanosSeconds).add(numberOfDays.multiply(secondsPerDay)));
}
}
return result;
}
public static Value truncateDate(String datePartStr, Value valueDate) {
int timeUnit = getDatePart(datePartStr);
long[] fieldDateAndTime = DateTimeUtils.dateAndTimeFromValue(valueDate);
long dateValue = fieldDateAndTime[0];
long timeNanosRetrieved = fieldDateAndTime[1];
long timeNanos;
switch (timeUnit) {
case MICROSECOND:
long nanoInMicroSecond = 1_000L;
long microseconds = timeNanosRetrieved / nanoInMicroSecond;
timeNanos = microseconds * nanoInMicroSecond;
break;
case MILLISECOND:
long nanoInMilliSecond = 1_000_000L;
long milliseconds = timeNanosRetrieved / nanoInMilliSecond;
timeNanos = milliseconds * nanoInMilliSecond;
break;
case SECOND:
long seconds = timeNanosRetrieved / NANOS_PER_SECOND;
timeNanos = seconds * NANOS_PER_SECOND;
break;
case MINUTE:
long minutes = timeNanosRetrieved / NANOS_PER_MINUTE;
timeNanos = minutes * NANOS_PER_MINUTE;
break;
case HOUR:
long hours = timeNanosRetrieved / NANOS_PER_HOUR;
timeNanos = hours * NANOS_PER_HOUR;
break;
case DAY_OF_MONTH:
timeNanos = 0L;
break;
case WEEK:
long absoluteDay = DateTimeUtils.absoluteDayFromDateValue(dateValue);
int dayOfWeek = DateTimeUtils.getDayOfWeekFromAbsolute(absoluteDay, 1);
if (dayOfWeek != 1) {
dateValue = DateTimeUtils.dateValueFromAbsoluteDay(absoluteDay - dayOfWeek + 1);
}
timeNanos = 0L;
break;
case MONTH: {
long year = DateTimeUtils.yearFromDateValue(dateValue);
int month = DateTimeUtils.monthFromDateValue(dateValue);
dateValue = DateTimeUtils.dateValue(year, month, 1);
timeNanos = 0L;
break;
}
case QUARTER: {
long year = DateTimeUtils.yearFromDateValue(dateValue);
int month = DateTimeUtils.monthFromDateValue(dateValue);
month = ((month - 1) / 3) * 3 + 1;
dateValue = DateTimeUtils.dateValue(year, month, 1);
timeNanos = 0L;
break;
}
case YEAR: {
long year = DateTimeUtils.yearFromDateValue(dateValue);
dateValue = DateTimeUtils.dateValue(year, 1, 1);
timeNanos = 0L;
break;
}
case DECADE: {
long year = DateTimeUtils.yearFromDateValue(dateValue);
year = (year / 10) * 10;
dateValue = DateTimeUtils.dateValue(year, 1, 1);
timeNanos = 0L;
break;
}
case CENTURY: {
long year = DateTimeUtils.yearFromDateValue(dateValue);
year = ((year - 1) / 100) * 100 + 1;
dateValue = DateTimeUtils.dateValue(year, 1, 1);
timeNanos = 0L;
break;
}
case MILLENNIUM: {
long year = DateTimeUtils.yearFromDateValue(dateValue);
year = ((year - 1) / 1000) * 1000 + 1;
dateValue = DateTimeUtils.dateValue(year, 1, 1);
timeNanos = 0L;
break;
}
default:
throw DbException.getUnsupportedException(datePartStr);
}
Value result;
if (valueDate instanceof ValueTimestampTimeZone) {
ValueTimestampTimeZone vTmp = (ValueTimestampTimeZone) valueDate;
result = ValueTimestampTimeZone.fromDateValueAndNanos(dateValue, timeNanos, vTmp.getTimeZoneOffsetMins());
} else {
result = ValueTimestamp.fromDateValueAndNanos(dateValue, timeNanos);
}
return result;
}
public static String formatDateTime(java.util.Date date, String format, String locale, String timeZone) {
SimpleDateFormat dateFormat = getDateFormat(format, locale, timeZone);
synchronized (dateFormat) {
return dateFormat.format(date);
}
}
private static SimpleDateFormat getDateFormat(String format, String locale, String timeZone) {
try {
SimpleDateFormat df;
if (locale == null) {
df = new SimpleDateFormat(format);
} else {
Locale l = new Locale(locale);
df = new SimpleDateFormat(format, l);
}
if (timeZone != null) {
df.setTimeZone(TimeZone.getTimeZone(timeZone));
}
return df;
} catch (Exception e) {
throw DbException.get(ErrorCode.PARSE_ERROR_1, e, format + "/" + locale + "/" + timeZone);
}
}
public static int getDatePart(String part) {
Integer p = DATE_PART.get(StringUtils.toUpperEnglish(part));
if (p == null) {
throw DbException.getInvalidValueException("date part", part);
}
return p;
}
public static int getIntDatePart(Value date, int field, Mode mode) {
if (date instanceof ValueInterval) {
ValueInterval interval = (ValueInterval) date;
IntervalQualifier qualifier = interval.getQualifier();
boolean negative = interval.isNegative();
long leading = interval.getLeading(), remaining = interval.getRemaining();
long v;
switch (field) {
case YEAR:
v = IntervalUtils.yearsFromInterval(qualifier, negative, leading, remaining);
break;
case MONTH:
v = IntervalUtils.monthsFromInterval(qualifier, negative, leading, remaining);
break;
case DAY_OF_MONTH:
case DAY_OF_YEAR:
v = IntervalUtils.daysFromInterval(qualifier, negative, leading, remaining);
break;
case HOUR:
v = IntervalUtils.hoursFromInterval(qualifier, negative, leading, remaining);
break;
case MINUTE:
v = IntervalUtils.minutesFromInterval(qualifier, negative, leading, remaining);
break;
case SECOND:
v = IntervalUtils.nanosFromInterval(qualifier, negative, leading, remaining) / NANOS_PER_SECOND;
break;
case MILLISECOND:
v = IntervalUtils.nanosFromInterval(qualifier, negative, leading, remaining) / 1_000_000 % 1_000;
break;
case MICROSECOND:
v = IntervalUtils.nanosFromInterval(qualifier, negative, leading, remaining) / 1_000 % 1_000_000;
break;
case NANOSECOND:
v = IntervalUtils.nanosFromInterval(qualifier, negative, leading, remaining) % NANOS_PER_SECOND;
break;
default:
throw DbException.getUnsupportedException("getDatePart(" + date + ", " + field + ')');
}
return (int) v;
} else {
long[] a = DateTimeUtils.dateAndTimeFromValue(date);
long dateValue = a[0];
long timeNanos = a[1];
switch (field) {
case YEAR:
return DateTimeUtils.yearFromDateValue(dateValue);
case MONTH:
return DateTimeUtils.monthFromDateValue(dateValue);
case DAY_OF_MONTH:
return DateTimeUtils.dayFromDateValue(dateValue);
case HOUR:
return (int) (timeNanos / NANOS_PER_HOUR % 24);
case MINUTE:
return (int) (timeNanos / NANOS_PER_MINUTE % 60);
case SECOND:
return (int) (timeNanos / NANOS_PER_SECOND % 60);
case MILLISECOND:
return (int) (timeNanos / 1_000_000 % 1_000);
case MICROSECOND:
return (int) (timeNanos / 1_000 % 1_000_000);
case NANOSECOND:
return (int) (timeNanos % NANOS_PER_SECOND);
case DAY_OF_YEAR:
return DateTimeUtils.getDayOfYear(dateValue);
case DAY_OF_WEEK:
return DateTimeUtils.getSundayDayOfWeek(dateValue);
case DOW: {
int dow = DateTimeUtils.getSundayDayOfWeek(dateValue);
if (mode.getEnum() == ModeEnum.PostgreSQL) {
dow--;
}
return dow;
}
case WEEK:
GregorianCalendar gc = DateTimeUtils.getCalendar();
return DateTimeUtils.getWeekOfYear(dateValue, gc.getFirstDayOfWeek() - 1,
gc.getMinimalDaysInFirstWeek());
case QUARTER:
return (DateTimeUtils.monthFromDateValue(dateValue) - 1) / 3 + 1;
case ISO_YEAR:
return DateTimeUtils.getIsoWeekYear(dateValue);
case ISO_WEEK:
return DateTimeUtils.getIsoWeekOfYear(dateValue);
case ISO_DAY_OF_WEEK:
return DateTimeUtils.getIsoDayOfWeek(dateValue);
case TIMEZONE_HOUR:
case TIMEZONE_MINUTE: {
int offsetMinutes;
if (date instanceof ValueTimestampTimeZone) {
offsetMinutes = ((ValueTimestampTimeZone) date).getTimeZoneOffsetMins();
} else {
offsetMinutes = DateTimeUtils.getTimeZoneOffsetMillis(null, dateValue, timeNanos);
}
if (field == TIMEZONE_HOUR) {
return offsetMinutes / 60;
}
return offsetMinutes % 60;
}
}
}
throw DbException.getUnsupportedException("getDatePart(" + date + ", " + field + ')');
}
public static String[] getMonthsAndWeeks(int field) {
String[][] result = MONTHS_AND_WEEKS;
if (result == null) {
result = new String[2][];
DateFormatSymbols dfs = DateFormatSymbols.getInstance(Locale.ENGLISH);
result[0] = dfs.getMonths();
result[1] = dfs.getWeekdays();
MONTHS_AND_WEEKS = result;
}
return result[field];
}
public static boolean isDatePart(String part) {
return DATE_PART.containsKey(StringUtils.toUpperEnglish(part));
}
public static java.util.Date parseDateTime(String date, String format, String locale, String timeZone) {
SimpleDateFormat dateFormat = getDateFormat(format, locale, timeZone);
try {
synchronized (dateFormat) {
return dateFormat.parse(date);
}
} catch (Exception e) {
throw DbException.get(ErrorCode.PARSE_ERROR_1, e, date);
}
}
private static long weekdiff(long absolute1, long absolute2, int firstDayOfWeek) {
absolute1 += 4 - firstDayOfWeek;
long r1 = absolute1 / 7;
if (absolute1 < 0 && (r1 * 7 != absolute1)) {
r1--;
}
absolute2 += 4 - firstDayOfWeek;
long r2 = absolute2 / 7;
if (absolute2 < 0 && (r2 * 7 != absolute2)) {
r2--;
}
return r2 - r1;
}
private DateTimeFunctions() {
}
}