/*
* � Copyright FOCONIS AG, 2014
*
* 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.openntf.formula.function;
import java.util.Locale;
import java.util.Map;
import java.util.TreeSet;
import org.openntf.formula.DateTime;
import org.openntf.formula.Formatter;
import org.openntf.formula.FormulaContext;
import org.openntf.formula.Function;
import org.openntf.formula.FunctionFactory;
import org.openntf.formula.FunctionSet;
import org.openntf.formula.ValueHolder;
import org.openntf.formula.annotation.ParamCount;
import com.ibm.icu.util.Calendar;
public enum DateTimeFunctions {
;
public static class Functions extends FunctionSet {
private static final Map<String, Function> functionSet = FunctionFactory.getFunctions(DateTimeFunctions.class);
@Override
public Map<String, Function> getFunctions() {
return functionSet;
}
}
/*----------------------------------------------------------------------------*/
/*
* @Today, @Tomorrow, @Yesterday, @Now
*/
/*----------------------------------------------------------------------------*/
@ParamCount(0)
public static ValueHolder atToday(final FormulaContext ctx) {
return todayTomorrYester(ctx, "TODAY");
}
/*----------------------------------------------------------------------------*/
@ParamCount(0)
public static ValueHolder atTomorrow(final FormulaContext ctx) {
return todayTomorrYester(ctx, "TOMORROW");
}
/*----------------------------------------------------------------------------*/
@ParamCount(0)
public static ValueHolder atYesterday(final FormulaContext ctx) {
return todayTomorrYester(ctx, "YESTERDAY");
}
/*----------------------------------------------------------------------------*/
private static ValueHolder todayTomorrYester(final FormulaContext ctx, final String which) {
return ValueHolder.valueOf(ctx.getFormatter().parseDate(which));
}
/*----------------------------------------------------------------------------*/
@ParamCount({ 0, 2 })
public static ValueHolder atNow(final FormulaContext ctx, final ValueHolder params[]) {
if (params == null || params.length == 0) {
DateTime sdt = getSDTDefaultLocale(ctx);
sdt.setNow();
return ValueHolder.valueOf(sdt);
}
throw new UnsupportedOperationException("@Now with parameters isn't yet implemented");
}
/*----------------------------------------------------------------------------*/
private static DateTime getSDTDefaultLocale(final FormulaContext ctx) {
return ctx.getFormatter().getNewSDTInstance();
}
/*----------------------------------------------------------------------------*/
private static DateTime getSDTCopy(final FormulaContext ctx, final DateTime sdt) {
return ctx.getFormatter().getCopyOfSDTInstance(sdt);
}
/*----------------------------------------------------------------------------*/
/*
* @Year, @Month, @Day, @Hour, @Minute, @Second, @Weekday
*/
/*----------------------------------------------------------------------------*/
@ParamCount(1)
public static int atYear(final DateTime dt) {
return dt.toJavaCal().get(Calendar.YEAR);
}
/*----------------------------------------------------------------------------*/
@ParamCount(1)
public static int atMonth(final DateTime dt) {
return dt.toJavaCal().get(Calendar.MONTH) + 1;
}
/*----------------------------------------------------------------------------*/
@ParamCount(1)
public static int atDay(final DateTime dt) {
return dt.toJavaCal().get(Calendar.DAY_OF_MONTH);
}
/*----------------------------------------------------------------------------*/
@ParamCount(1)
public static int atHour(final DateTime dt) {
return dt.toJavaCal().get(Calendar.HOUR_OF_DAY);
}
/*----------------------------------------------------------------------------*/
@ParamCount(1)
public static int atMinute(final DateTime dt) {
return dt.toJavaCal().get(Calendar.MINUTE);
}
/*----------------------------------------------------------------------------*/
@ParamCount(1)
public static int atSecond(final DateTime dt) {
return dt.toJavaCal().get(Calendar.SECOND);
}
/*----------------------------------------------------------------------------*/
@ParamCount(1)
public static int atWeekday(final DateTime dt) {
return dt.toJavaCal().get(Calendar.DAY_OF_WEEK);
}
/*----------------------------------------------------------------------------*/
/*
* @Date, @Time, @TimeMerge
*/
/*----------------------------------------------------------------------------*/
@ParamCount({ 1, 6 })
public static ValueHolder atDate(final FormulaContext ctx, final ValueHolder params[]) {
if (params.length == 2)
throw new IllegalArgumentException("Expected: 1, 3, or 6 parameters");
if (params.length >= 3) {
DateTime sdt = getSDTDefaultLocale(ctx);
sdt.setLocalDate(params[0].getInt(0), params[1].getInt(0), params[2].getInt(0));
// 4 or 5 parameters are accepted by Lotus, but parameters 4 and 5 are ignored
if (params.length == 6)
sdt.setLocalTime(params[3].getInt(0), params[4].getInt(0), params[5].getInt(0), 0);
else
sdt.setAnyTime();
return ValueHolder.valueOf(sdt); // Multiple values are accepted, but ignored by Lotus
}
ValueHolder vh = params[0]; //Remains: length=1, which works completely different
ValueHolder ret = ValueHolder.createValueHolder(DateTime.class, vh.size);
for (int i = 0; i < vh.size; i++)
ret.add(getSDTCopy(ctx, vh.getDateTime(i)));
return ret;
}
/*----------------------------------------------------------------------------*/
@ParamCount({ 1, 6 })
public static ValueHolder atTime(final FormulaContext ctx, final ValueHolder params[]) {
if (params.length == 2)
throw new IllegalArgumentException("Expected: 1, 3, or 6 parameters");
// 4 or 5 parameters are accepted by Lotus, but they are ignored
if (params.length >= 3 && params.length <= 5) { // I was surprised.
DateTime sdt = getSDTDefaultLocale(ctx);
sdt.setAnyDate();
sdt.setAnyTime();
return ValueHolder.valueOf(sdt);
}
if (params.length == 6) // I was surprised once more!
return atDate(ctx, params);
ValueHolder vh = params[0]; //Remains: length=1, which works completely different
ValueHolder ret = ValueHolder.createValueHolder(DateTime.class, vh.size);
for (int i = 0; i < vh.size; i++) {
DateTime sdt = getSDTCopy(ctx, vh.getDateTime(i));
sdt.setAnyDate();
ret.add(sdt);
}
return ret;
}
/*----------------------------------------------------------------------------*/
@ParamCount({ 2, 3 })
public static ValueHolder atTimeMerge(final FormulaContext ctx, final ValueHolder params[]) {
if (params.length == 3)
throw new UnsupportedOperationException("@TimeMerge with 3 parameters not yet implemented");
ValueHolder dates = params[0];
ValueHolder times = params[1];
ValueHolder ret = ValueHolder.createValueHolder(DateTime.class, dates.size);
for (int i = 0; i < dates.size; i++) { // If there are more times than dates, they are ignored by Lotus
DateTime date = dates.getDateTime(i);
DateTime time = times.getDateTime(i);
Calendar calDate = date.toJavaCal();
Calendar calTime = time.toJavaCal();
DateTime sdt = getSDTDefaultLocale(ctx);
if (date.isAnyDate())
sdt.setAnyDate();
else
sdt.setLocalDate(calDate.get(Calendar.YEAR), calDate.get(Calendar.MONTH) + 1, calDate.get(Calendar.DAY_OF_MONTH));
if (time.isAnyTime())
sdt.setAnyTime();
else
sdt.setLocalTime(calTime.get(Calendar.HOUR_OF_DAY), calTime.get(Calendar.MINUTE), calTime.get(Calendar.SECOND),
calTime.get(Calendar.MILLISECOND));
ret.add(sdt);
}
return ret;
}
/*----------------------------------------------------------------------------*/
/*
* @Zone, @TimeZoneToText, @TimeToTextInZone
*/
/*----------------------------------------------------------------------------*/
// @ParamCount({ 0, 1 })
// public static ValueHolder atZone(final FormulaContext ctx, final ValueHolder params[]) {
// throw new UnsupportedOperationException("Method not yet implemented");
// }
//
// /*----------------------------------------------------------------------------*/
// @ParamCount({ 1, 2 })
// public static ValueHolder atTimeZoneToText(final FormulaContext ctx, final ValueHolder params[]) {
// throw new UnsupportedOperationException("Method not yet implemented");
// }
//
// /*----------------------------------------------------------------------------*/
// @ParamCount({ 2, 3 })
// public static ValueHolder atTimeToTextInZone(final FormulaContext ctx, final ValueHolder params[]) {
// throw new UnsupportedOperationException("Method not yet implemented");
// }
/*----------------------------------------------------------------------------*/
/*
* @BusinessDays
*/
/*----------------------------------------------------------------------------*/
@ParamCount({ 2, 4 })
public static ValueHolder atBusinessDays(final FormulaContext ctx, final ValueHolder params[]) {
ValueHolder fromDays = params[0];
ValueHolder toDays = params[1];
boolean[] excludeDays = new boolean[8];
for (int i = 0; i < 8; i++)
excludeDays[i] = false;
if (params.length >= 3) {
ValueHolder exclVH = params[2];
for (int i = 0; i < exclVH.size; i++) {
int ex = exclVH.getInt(i);
if (ex >= 1 && ex <= 7)
excludeDays[ex] = true;
}
}
TreeSet<DateTime> excludeDates = new TreeSet<DateTime>(fromDays.getDateTime(0));
if (params.length == 4) {
ValueHolder exclVH = params[3];
for (int i = 0; i < exclVH.size; i++) {
DateTime sdt = exclVH.getDateTime(i);
if (sdt.isAnyDate())
continue;
if (!sdt.isAnyTime()) {
sdt = getSDTCopy(ctx, sdt);
sdt.setAnyTime();
}
excludeDates.add(sdt);
}
}
int max = (fromDays.size >= toDays.size) ? fromDays.size : toDays.size;
ValueHolder ret = ValueHolder.createValueHolder(int.class, max);
for (int i = 0; i < max; i++) {
DateTime sdtFrom = fromDays.getDateTime(i);
DateTime sdtTo = toDays.getDateTime(i);
int busDays;
if (sdtFrom.isAnyDate() || sdtTo.isAnyDate())
busDays = -1;
else
busDays = calcBusDays(ctx, sdtFrom, sdtTo, excludeDays, excludeDates);
ret.add(busDays);
}
return ret;
}
/*----------------------------------------------------------------------------*/
private static int calcBusDays(final FormulaContext ctx, DateTime sdtFrom, DateTime sdtTo, final boolean[] excludeDays,
final TreeSet<DateTime> excludeDates) {
sdtFrom = getSDTCopy(ctx, sdtFrom);
sdtFrom.setAnyTime();
if (!sdtTo.isAnyTime()) {
sdtTo = getSDTCopy(ctx, sdtTo);
sdtTo.setAnyTime();
}
if (sdtFrom.compare(sdtFrom, sdtTo) > 0)
return -1;
int ret = 0;
do {
if (!excludeDays[sdtFrom.toJavaCal().get(Calendar.DAY_OF_WEEK)] && !excludeDates.contains(sdtFrom))
ret++;
sdtFrom.adjustDay(1);
} while (sdtFrom.compare(sdtFrom, sdtTo) <= 0);
return ret;
}
/*----------------------------------------------------------------------------*/
/*
* @Adjust
*/
/*----------------------------------------------------------------------------*/
@ParamCount({ 7, 8 })
public static ValueHolder atAdjust(final FormulaContext ctx, final ValueHolder params[]) {
if (params.length == 8)
throw new UnsupportedOperationException("@Adjust with 8 parameters not yet implemented");
ValueHolder toAdjust = params[0];
int adjustYears = params[1].getInt(0); // Multiple "Adjustors" are ignored by Lotus
int adjustMonths = params[2].getInt(0);
int adjustDays = params[3].getInt(0);
int adjustHours = params[4].getInt(0);
int adjustMinutes = params[5].getInt(0);
int adjustSeconds = params[6].getInt(0);
ValueHolder ret = ValueHolder.createValueHolder(DateTime.class, toAdjust.size);
for (int i = 0; i < toAdjust.size; i++) {
DateTime sdt = getSDTCopy(ctx, toAdjust.getDateTime(i));
if (!sdt.isAnyDate()) {
if (adjustYears != 0)
sdt.adjustYear(adjustYears);
if (adjustMonths != 0)
sdt.adjustMonth(adjustMonths);
if (adjustDays != 0)
sdt.adjustDay(adjustDays);
}
if (!sdt.isAnyTime()) {
if (adjustHours != 0)
sdt.adjustHour(adjustHours);
if (adjustMinutes != 0)
sdt.adjustMinute(adjustMinutes);
if (adjustSeconds != 0)
sdt.adjustSecond(adjustSeconds);
}
ret.add(sdt);
}
return ret;
}
/*----------------------------------------------------------------------------*/
/*
* @ListLocales, @SetLocale, @PTest (for testing with a different Locale)
*/
/*----------------------------------------------------------------------------*/
private static DateTime getSDTLocalSetLocale() {
return org.openntf.formula.Formulas.getFormatter(iLocale).getNewSDTInstance();
}
/*----------------------------------------------------------------------------*/
/*private*/static Locale iLocale = null;
private static String[] localStrs = { "GERMANY", "US", "CANADA", //
"UK", "CHINA", "FRANCE" };
private static Locale[] locales = { Locale.GERMANY, Locale.US, Locale.CANADA, //
Locale.UK, Locale.CHINA, Locale.FRANCE };
/*----------------------------------------------------------------------------*/
@ParamCount(0)
public static ValueHolder atListLocales() {
ValueHolder ret = ValueHolder.createValueHolder(String.class, localStrs.length);
for (int i = 0; i < localStrs.length; i++)
ret.add(localStrs[i]);
return ret;
}
/*----------------------------------------------------------------------------*/
@ParamCount(1)
public static ValueHolder atSetLocale(final FormulaContext ctx, final ValueHolder params[]) {
String toSetS = params[0].getString(0);
if (toSetS == "") {
iLocale = null;
return ctx.TRUE;
}
Locale toSet = null;
for (int i = 0; i < localStrs.length; i++)
if (toSetS.equalsIgnoreCase(localStrs[i])) {
toSet = locales[i];
break;
}
if (toSet != null)
iLocale = toSet;
return toSet != null ? ctx.TRUE : ctx.FALSE;
}
/*----------------------------------------------------------------------------*/
@ParamCount(1)
public static String atDTTest(final String s) {
DateTime sdt = getSDTLocalSetLocale();
sdt.setLocalTime(s);
return sdt.getLocalTime();
}
/*----------------------------------------------------------------------------*/
@ParamCount(1)
public static String atNTest(final String s) {
Formatter formatter = org.openntf.formula.Formulas.getFormatter(iLocale);
Number n = formatter.parseNumber(s, true);
return formatter.formatNumber(n);
}
/*----------------------------------------------------------------------------*/
}