113 lines
3.7 KiB
Java
113 lines
3.7 KiB
Java
/* ====================================================================
|
|
Licensed to the Apache Software Foundation (ASF) under one or more
|
|
contributor license agreements. See the NOTICE file distributed with
|
|
this work for additional information regarding copyright ownership.
|
|
The ASF licenses this file to You 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.apache.poi.ss.formula.functions;
|
|
|
|
import java.util.Calendar;
|
|
|
|
import org.apache.poi.ss.formula.eval.ErrorEval;
|
|
import org.apache.poi.ss.formula.eval.EvaluationException;
|
|
import org.apache.poi.ss.formula.eval.NumberEval;
|
|
import org.apache.poi.ss.formula.eval.ValueEval;
|
|
import org.apache.poi.ss.usermodel.DateUtil;
|
|
import org.apache.poi.util.LocaleUtil;
|
|
|
|
|
|
/**
|
|
* Implementation for the Excel function DATE
|
|
*/
|
|
public final class DateFunc extends Fixed3ArgFunction {
|
|
public static final Function instance = new DateFunc();
|
|
|
|
private DateFunc() {
|
|
// no fields to initialise
|
|
}
|
|
public ValueEval evaluate(int srcRowIndex, int srcColumnIndex, ValueEval arg0, ValueEval arg1,
|
|
ValueEval arg2) {
|
|
double result;
|
|
try {
|
|
double d0 = NumericFunction.singleOperandEvaluate(arg0, srcRowIndex, srcColumnIndex);
|
|
double d1 = NumericFunction.singleOperandEvaluate(arg1, srcRowIndex, srcColumnIndex);
|
|
double d2 = NumericFunction.singleOperandEvaluate(arg2, srcRowIndex, srcColumnIndex);
|
|
result = evaluate(getYear(d0), (int) (d1 - 1), (int) d2);
|
|
NumericFunction.checkValue(result);
|
|
} catch (EvaluationException e) {
|
|
return e.getErrorEval();
|
|
}
|
|
return new NumberEval(result);
|
|
}
|
|
|
|
/**
|
|
* Note - works with Java Calendar months, not Excel months
|
|
*/
|
|
private static double evaluate(int year, int month, int pDay) throws EvaluationException {
|
|
// We don't support negative years yet
|
|
if (year < 0) {
|
|
throw new EvaluationException(ErrorEval.VALUE_INVALID);
|
|
}
|
|
// Negative months are fairly easy
|
|
while (month < 0) {
|
|
year--;
|
|
month += 12;
|
|
}
|
|
// Negative days are handled by the Java Calendar
|
|
|
|
// Excel has bugs around leap years in 1900, handle them
|
|
// Special case for the non-existant 1900 leap year
|
|
if (year == 1900 && month == Calendar.FEBRUARY && pDay == 29) {
|
|
return 60.0;
|
|
}
|
|
|
|
// If they give a date in 1900 in Jan/Feb, with the days
|
|
// putting it past the leap year, adjust
|
|
int day = pDay;
|
|
if (year == 1900) {
|
|
if ((month == Calendar.JANUARY && day >= 60) ||
|
|
(month == Calendar.FEBRUARY && day >= 30)) {
|
|
day--;
|
|
}
|
|
}
|
|
|
|
// Turn this into a Java date
|
|
Calendar c = LocaleUtil.getLocaleCalendar(year, month, day);
|
|
|
|
// Handle negative days of the week, that pull us across
|
|
// the 29th of Feb 1900
|
|
if (pDay < 0 && c.get(Calendar.YEAR) == 1900 &&
|
|
month > Calendar.FEBRUARY &&
|
|
c.get(Calendar.MONTH) < Calendar.MARCH) {
|
|
c.add(Calendar.DATE, 1);
|
|
}
|
|
|
|
// TODO Identify if we're doing 1900 or 1904 date windowing
|
|
boolean use1904windowing = false;
|
|
|
|
// Have this Java date turned back into an Excel one
|
|
return DateUtil.getExcelDate(c.getTime(), use1904windowing);
|
|
}
|
|
|
|
private static int getYear(double d) {
|
|
int year = (int)d;
|
|
|
|
if (year < 0) {
|
|
return -1;
|
|
}
|
|
|
|
return year < 1900 ? 1900 + year : year;
|
|
}
|
|
}
|