*/
public interface EvalContext
{
+ public TemporalConfig getTemporalConfig();
+
public Value.Type getResultType();
public SimpleDateFormat createDateFormat(String formatStr);
--- /dev/null
+/*
+Copyright (c) 2017 James Ahlborn
+
+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.healthmarketscience.jackcess.expr;
+
+/**
+ *
+ * @author James Ahlborn
+ */
+public class TemporalConfig
+{
+ public static final String US_DATE_FORMAT = "M/d/yyyy";
+ public static final String US_TIME_FORMAT_12 = "hh:mm:ss a";
+ public static final String US_TIME_FORMAT_24 = "HH:mm:ss";
+
+ public static final TemporalConfig US_TEMPORAL_CONFIG = new TemporalConfig(
+ US_DATE_FORMAT, US_TIME_FORMAT_12, US_TIME_FORMAT_24, '/', ':');
+
+ private final String _dateFormat;
+ private final String _timeFormat12;
+ private final String _timeFormat24;
+ private final char _dateSeparator;
+ private final char _timeSeparator;
+ private final String _dateTimeFormat12;
+ private final String _dateTimeFormat24;
+
+ public TemporalConfig(String dateFormat, String timeFormat12,
+ String timeFormat24, char dateSeparator,
+ char timeSeparator)
+ {
+ _dateFormat = dateFormat;
+ _timeFormat12 = timeFormat12;
+ _timeFormat24 = timeFormat24;
+ _dateSeparator = dateSeparator;
+ _timeSeparator = timeSeparator;
+ _dateTimeFormat12 = _dateFormat + " " + _timeFormat12;
+ _dateTimeFormat24 = _dateFormat + " " + _timeFormat24;
+ }
+
+ public String getDateFormat() {
+ return _dateFormat;
+ }
+
+ public String getTimeFormat12() {
+ return _timeFormat12;
+ }
+
+ public String getTimeFormat24() {
+ return _timeFormat24;
+ }
+
+ public String getDateTimeFormat12() {
+ return _dateTimeFormat12;
+ }
+
+ public String getDateTimeFormat24() {
+ return _dateTimeFormat24;
+ }
+
+ public String getDefaultDateFormat() {
+ return getDateFormat();
+ }
+
+ public String getDefaultTimeFormat() {
+ return getTimeFormat12();
+ }
+
+ public String getDefaultDateTimeFormat() {
+ return getDateTimeFormat12();
+ }
+
+ public char getDateSeparator() {
+ return _dateSeparator;
+ }
+
+ public char getTimeSeparator() {
+ return _timeSeparator;
+ }
+}
-// Copyright (c) 2016 Dell Boomi, Inc.
+/*
+Copyright (c) 2017 James Ahlborn
+
+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.healthmarketscience.jackcess.impl.expr;
-// Copyright (c) 2016 Dell Boomi, Inc.
+/*
+Copyright (c) 2017 James Ahlborn
+
+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.healthmarketscience.jackcess.impl.expr;
-import com.healthmarketscience.jackcess.expr.Value;
/**
*
String fmtStr = null;
switch(type) {
case DATE:
- fmtStr = ExpressionTokenizer.DATE_FORMAT;
+ fmtStr = ctx.getTemporalConfig().getDefaultDateFormat();
break;
case TIME:
- fmtStr = ExpressionTokenizer.TIME_FORMAT_24;
+ fmtStr = ctx.getTemporalConfig().getDefaultTimeFormat();
break;
case DATE_TIME:
- fmtStr = ExpressionTokenizer.DATE_TIME_FORMAT_24;
+ fmtStr = ctx.getTemporalConfig().getDefaultDateTimeFormat();
break;
default:
throw new RuntimeException("Unexpected type " + type);
package com.healthmarketscience.jackcess.impl.expr;
-import java.math.BigDecimal;
import java.text.DateFormat;
import java.text.FieldPosition;
import java.text.ParseException;
import static com.healthmarketscience.jackcess.impl.expr.Expressionator.*;
import com.healthmarketscience.jackcess.expr.Value;
+import com.healthmarketscience.jackcess.expr.TemporalConfig;
/**
private static final char DATE_LIT_QUOTE_CHAR = '#';
private static final char EQUALS_CHAR = '=';
- static final String DATE_FORMAT = "M/d/yyyy";
- static final String TIME_FORMAT_24 = "HH:mm:ss";
- static final String TIME_FORMAT_12 = "hh:mm:ss a";
- static final String DATE_TIME_FORMAT_24 = DATE_FORMAT + " " + TIME_FORMAT_24;
- static final String DATE_TIME_FORMAT_12 = DATE_FORMAT + " " + TIME_FORMAT_12;
private static final int AMPM_SUFFIX_LEN = 3;
private static final String AM_SUFFIX = " am";
private static final String PM_SUFFIX = " pm";
// access times are based on this date (not the UTC base)
private static final String BASE_DATE = "12/30/1899 ";
+ private static final String BASE_DATE_FMT = "M/d/yyyy";
private static final byte IS_OP_FLAG = 0x01;
private static final byte IS_COMP_FLAG = 0x02;
private static Token parseDateLiteralString(ExprBuf buf)
{
+ TemporalConfig cfg = buf.getTemporalConfig();
String dateStr = parseStringUntil(buf, DATE_LIT_QUOTE_CHAR, null);
- boolean hasDate = (dateStr.indexOf('/') >= 0);
- boolean hasTime = (dateStr.indexOf(':') >= 0);
+ boolean hasDate = (dateStr.indexOf(cfg.getDateSeparator()) >= 0);
+ boolean hasTime = (dateStr.indexOf(cfg.getTimeSeparator()) >= 0);
boolean hasAmPm = false;
if(hasTime) {
private DateFormat _dateTimeFmt12;
private DateFormat _timeFmt24;
private DateFormat _dateTimeFmt24;
+ private String _baseDate;
private final StringBuilder _scratch = new StringBuilder();
private ExprBuf(String str, ParseContext ctx) {
return _scratch;
}
+ public TemporalConfig getTemporalConfig() {
+ return _ctx.getTemporalConfig();
+ }
+
public DateFormat getDateFormat() {
if(_dateFmt == null) {
- _dateFmt = _ctx.createDateFormat(DATE_FORMAT);
+ _dateFmt = _ctx.createDateFormat(getTemporalConfig().getDateFormat());
}
return _dateFmt;
}
public DateFormat getTimeFormat12() {
if(_timeFmt12 == null) {
_timeFmt12 = new TimeFormat(
- getDateTimeFormat12(), _ctx.createDateFormat(TIME_FORMAT_12));
+ getDateTimeFormat12(), _ctx.createDateFormat(
+ getTemporalConfig().getTimeFormat12()),
+ getBaseDate());
}
return _timeFmt12;
}
public DateFormat getDateTimeFormat12() {
if(_dateTimeFmt12 == null) {
- _dateTimeFmt12 = _ctx.createDateFormat(DATE_TIME_FORMAT_12);
+ _dateTimeFmt12 = _ctx.createDateFormat(
+ getTemporalConfig().getDateTimeFormat12());
}
return _dateTimeFmt12;
}
public DateFormat getTimeFormat24() {
if(_timeFmt24 == null) {
_timeFmt24 = new TimeFormat(
- getDateTimeFormat24(), _ctx.createDateFormat(TIME_FORMAT_24));
+ getDateTimeFormat24(), _ctx.createDateFormat(
+ getTemporalConfig().getTimeFormat24()),
+ getBaseDate());
}
return _timeFmt24;
}
public DateFormat getDateTimeFormat24() {
if(_dateTimeFmt24 == null) {
- _dateTimeFmt24 = _ctx.createDateFormat(DATE_TIME_FORMAT_24);
+ _dateTimeFmt24 = _ctx.createDateFormat(
+ getTemporalConfig().getDateTimeFormat24());
}
return _dateTimeFmt24;
}
+ private String getBaseDate() {
+ if(_baseDate == null) {
+ String dateFmt = getTemporalConfig().getDateFormat();
+ String baseDate = BASE_DATE;
+ if(!BASE_DATE_FMT.equals(dateFmt)) {
+ try {
+ // need to reformat the base date to the relevant date format
+ DateFormat df = _ctx.createDateFormat(BASE_DATE_FMT);
+ baseDate = getDateFormat().format(df.parse(baseDate));
+ } catch(Exception e) {
+ throw new IllegalStateException("Could not parse base date", e);
+ }
+ }
+ _baseDate = baseDate + " ";
+ }
+ return _baseDate;
+ }
+
@Override
public String toString() {
return "[char " + _pos + "] '" + _str + "'";
private static final class TimeFormat extends DateFormat
{
private static final long serialVersionUID = 0L;
+
private final DateFormat _parseDelegate;
private final DateFormat _fmtDelegate;
+ private final String _baseDate;
- private TimeFormat(DateFormat parseDelegate, DateFormat fmtDelegate)
+ private TimeFormat(DateFormat parseDelegate, DateFormat fmtDelegate,
+ String baseDate)
{
_parseDelegate = parseDelegate;
_fmtDelegate = fmtDelegate;
+ _baseDate = baseDate;
}
@Override
public Date parse(String source, ParsePosition pos) {
// we parse as a full date/time in order to get the correct "base date"
// used by access
- return _parseDelegate.parse(BASE_DATE + source, pos);
+ return _parseDelegate.parse(_baseDate + source, pos);
}
@Override
import com.healthmarketscience.jackcess.expr.Expression;
import com.healthmarketscience.jackcess.expr.Function;
import com.healthmarketscience.jackcess.expr.EvalContext;
+import com.healthmarketscience.jackcess.expr.TemporalConfig;
import com.healthmarketscience.jackcess.expr.Value;
import com.healthmarketscience.jackcess.impl.expr.ExpressionTokenizer.Token;
import com.healthmarketscience.jackcess.impl.expr.ExpressionTokenizer.TokenType;
}
public interface ParseContext {
+ public TemporalConfig getTemporalConfig();
public SimpleDateFormat createDateFormat(String formatStr);
public Function getExpressionFunction(String name);
}
public static final ParseContext DEFAULT_PARSE_CONTEXT = new ParseContext() {
+ public TemporalConfig getTemporalConfig() {
+ return TemporalConfig.US_TEMPORAL_CONFIG;
+ }
public SimpleDateFormat createDateFormat(String formatStr) {
return DatabaseBuilder.createDateFormat(formatStr);
}
case LIKE:
Token t = buf.next();
- // FIXME, create LITERAL_STRING TokenType?
- if(t.getType() != TokenType.LITERAL) {
+ if((t.getType() != TokenType.LITERAL) ||
+ (t.getValueType() != Value.Type.STRING)) {
throw new IllegalArgumentException("Missing Like pattern " + buf);
}
String patternStr = t.getValueStr();
import com.healthmarketscience.jackcess.TestUtil;
import com.healthmarketscience.jackcess.expr.Expression;
import com.healthmarketscience.jackcess.expr.Function;
+import com.healthmarketscience.jackcess.expr.TemporalConfig;
import junit.framework.TestCase;
/**
private static final class TestContext implements Expressionator.ParseContext
{
+ public TemporalConfig getTemporalConfig() {
+ return TemporalConfig.US_TEMPORAL_CONFIG;
+ }
public SimpleDateFormat createDateFormat(String formatStr) {
SimpleDateFormat sdf = DatabaseBuilder.createDateFormat(formatStr);
sdf.setTimeZone(TestUtil.TEST_TZ);