package water.rapids.ast.prims.time; import org.joda.time.DateTime; import org.joda.time.format.DateTimeFormatter; import water.MRTask; import water.fvec.Chunk; import water.fvec.Frame; import water.fvec.NewChunk; import water.fvec.Vec; import water.parser.BufferedString; import water.parser.ParseTime; import water.rapids.Env; import water.rapids.Val; import water.rapids.vals.ValFrame; import water.rapids.ast.AstPrimitive; import water.rapids.ast.AstRoot; /** * Convert a String to a Time (msec since Unix Epoch) via a given parse format */ public class AstAsDate extends AstPrimitive { @Override public String[] args() { return new String[]{"time", "format"}; } // (as.Date time format) @Override public int nargs() { return 1 + 2; } @Override public String str() { return "as.Date"; } @Override public ValFrame apply(Env env, Env.StackHelp stk, AstRoot asts[]) { Frame fr = stk.track(asts[1].exec(env)).getFrame(); Vec vec = fr.vecs()[0]; if (fr.vecs().length != 1 || !(vec.isCategorical() || vec.isString())) throw new IllegalArgumentException("as.Date requires a single column of factors or strings"); final String format = asts[2].exec(env).getStr(); if (format.isEmpty()) throw new IllegalArgumentException("as.Date requires a non-empty format string"); // check the format string more? final String[] dom = vec.domain(); final boolean isStr = dom == null && vec.isString(); assert isStr || dom != null : "as.Date error: domain is null, but vec is not String"; Frame fr2 = new MRTask() { private transient DateTimeFormatter _fmt; @Override public void setupLocal() { _fmt = ParseTime.forStrptimePattern(format).withZone(ParseTime.getTimezone()); } @Override public void map(Chunk c, NewChunk nc) { //done on each node in lieu of rewriting DateTimeFormatter as Iced String date; BufferedString tmpStr = new BufferedString(); for (int i = 0; i < c._len; ++i) { if (!c.isNA(i)) { if (isStr) date = c.atStr(tmpStr, i).toString(); else date = dom[(int) c.at8(i)]; nc.addNum(DateTime.parse(date, _fmt).getMillis(), 0); } else nc.addNA(); } } }.doAll(1, Vec.T_NUM, fr).outputFrame(fr._names, null); return new ValFrame(fr2); } }