/*
* 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 com.addthis.hydra.data.query.op;
import com.addthis.basis.util.LessStrings;
import com.addthis.bundle.core.Bundle;
import com.addthis.bundle.util.BundleColumnBinder;
import com.addthis.bundle.util.ValueUtil;
import com.addthis.bundle.value.ValueFactory;
import com.addthis.bundle.value.ValueObject;
import com.addthis.hydra.data.query.AbstractRowOp;
import org.joda.time.DateTime;
import org.joda.time.format.DateTimeFormat;
import org.joda.time.format.DateTimeFormatter;
import io.netty.channel.ChannelProgressivePromise;
/**
* <p>This query operation <span class="hydra-summary">transforms from one date format to another</span>.
* <p/>
* <p>The input and output date formats are specified using the <a href="http://joda-time.sourceforge.net/apidocs/org/joda/time/format/DateTimeFormat.html">DateTimeFormat</a></p>
* <p/>
* <pre>
* datef=incols:informat:outformat:outcol
* datef=0:yyMMdd:yymm would transform (090909 to 0909)
* </pre>
* <p><b>incols</b> is optionally a comma separated list of columns to be concatenated together.</p>
* <p>if <b>outcol<b> is not set, the first column of <b>incols</b> is used </p>
* <p></p><b>informat</b> and/or <b>outformat</b> can optionally be <i>unixmillis</i> to convert to or from a base10 unix millis epoch offset value.</p>
*
* @user-reference
* @hydra-name datef
*/
public class OpDateFormat extends AbstractRowOp {
private int[] incols;
private int outcol;
private DateTimeFormatter inFormat;
private DateTimeFormatter outFormat;
private int fromMillis; // base for conversion or 0
private int toMillis; // base for conversion or 0
public OpDateFormat(String args, ChannelProgressivePromise queryPromise) {
super(queryPromise);
try {
String[] opt = args.split(":");
if (opt.length >= 2) {
String[] cval = LessStrings.splitArray(opt[0], ",");
incols = new int[cval.length];
for (int i = 0; i < cval.length; i++) {
incols[i] = Integer.parseInt(cval[i]);
}
outcol = opt.length > 3 ? Integer.parseInt(opt[3]) : incols[0];
if ((fromMillis = parseMillis(opt[1])) == 0) {
inFormat = DateTimeFormat.forPattern(opt[1]);
}
if ((toMillis = parseMillis(opt[2])) == 0) {
outFormat = DateTimeFormat.forPattern(opt[2]);
}
}
} catch (Exception ex) {
ex.printStackTrace();
}
}
/**
* TODO future support format "unixmillis:base"
* but for now always use base 10
*/
private int parseMillis(String value) {
if (value.startsWith("unixmillis")) {
return 10;
} else {
return 0;
}
}
@Override
public Bundle rowOp(Bundle row) {
BundleColumnBinder binder = getSourceColumnBinder(row);
// concatenate columns
StringBuffer buf = new StringBuffer();
for (int i = 0; i < incols.length; i++) {
String s = ValueUtil.asNativeString(binder.getColumn(row, incols[i]));
if (s != null) {
buf.append(s);
}
}
// convert input
String sbuf = buf.toString();
DateTime dt = null;
if (fromMillis > 0) {
dt = new DateTime(Long.parseLong(sbuf, fromMillis));
} else {
dt = inFormat.parseDateTime(sbuf);
}
// convert and output
ValueObject out = null;
if (toMillis > 0) {
out = ValueFactory.create(dt.getMillis());
} else {
out = ValueFactory.create(outFormat.print(dt));
}
if (outcol >= row.getCount()) {
binder.appendColumn(row, out);
} else {
binder.setColumn(row, outcol, out);
}
return row;
}
}