diff --git a/bigiron/src/org/labkey/bigiron/mssql/MicrosoftSqlServer2016Dialect.java b/bigiron/src/org/labkey/bigiron/mssql/MicrosoftSqlServer2016Dialect.java index 44ba6912cc7..fccd108ec82 100644 --- a/bigiron/src/org/labkey/bigiron/mssql/MicrosoftSqlServer2016Dialect.java +++ b/bigiron/src/org/labkey/bigiron/mssql/MicrosoftSqlServer2016Dialect.java @@ -15,6 +15,7 @@ */ package org.labkey.bigiron.mssql; +import org.apache.commons.lang3.time.FastDateFormat; import org.apache.logging.log4j.Logger; import org.junit.Assert; import org.junit.Test; @@ -33,8 +34,6 @@ import java.sql.Statement; import java.sql.Timestamp; import java.sql.Types; -import java.time.ZoneId; -import java.time.format.DateTimeFormatter; import java.util.Calendar; import java.util.Date; import java.util.Map; @@ -45,7 +44,7 @@ public class MicrosoftSqlServer2016Dialect extends MicrosoftSqlServer2014Dialect private volatile String _language = null; private volatile String _dateFormat = null; - private volatile DateTimeFormatter _timestampFormatter = null; + private volatile FastDateFormat _timestampFormatter = null; @Override public void prepare(DbScope scope) @@ -66,7 +65,7 @@ public void prepare(DbScope scope) default -> throw new IllegalStateException("Unsupported date format: " + _dateFormat); }; - _timestampFormatter = DateTimeFormatter.ofPattern("yyyy-" + mdFormat + " HH:mm:ss.SSS"); + _timestampFormatter = FastDateFormat.getInstance("yyyy-" + mdFormat + " HH:mm:ss.SSS"); LOG.info("\n Language: {}\n DateFormat: {}", _language, _dateFormat); } @@ -93,7 +92,7 @@ public StatementWrapper getStatementWrapper(ConnectionWrapper conn, Statement st * so we send Timestamps as Strings. SQL Server is very picky about this format; for example, Timestamp.toString(), * which is basically ISO, is actually ambiguous and fails if language is French (e.g.). See Issue 51129. */ - private class TimestampStatementWrapper extends StatementWrapper + class TimestampStatementWrapper extends StatementWrapper { public TimestampStatementWrapper(ConnectionWrapper conn, Statement stmt) { @@ -212,7 +211,7 @@ private Object convert(Object x) private String convert(Timestamp ts) { - return _timestampFormatter.format(ts.toInstant().atZone(ZoneId.systemDefault())); + return _timestampFormatter.format(ts); } } @@ -224,7 +223,7 @@ public void testTimestamps() DbScope scope = DbScope.getLabKeyScope(); SqlDialect dialect = scope.getSqlDialect(); - if (dialect.isSqlServer() && dialect instanceof MicrosoftSqlServer2016Dialect) + if (dialect.isSqlServer() && dialect instanceof MicrosoftSqlServer2016Dialect ms2016Dialect) { try (Connection conn = DbScope.getLabKeyScope().getConnection()) { @@ -253,6 +252,15 @@ public void testTimestamps() statement.setObject("filterStartTimeStamp", ts); } } + + if (conn instanceof ConnectionWrapper cw) + { + // Test a few timestamp conversions. Need to accommodate mdy vs. dmy databases. + TimestampStatementWrapper wrapper = ms2016Dialect.new TimestampStatementWrapper(cw, null); + test(wrapper, "mdy".equals(ms2016Dialect._dateFormat) ? "1800-05-10 10:32:00.000" : "1800-10-05 10:32:00.000", "1800-05-10 10:32:00"); + test(wrapper, "mdy".equals(ms2016Dialect._dateFormat) ? "1800-05-10 10:32:00.647" : "1800-10-05 10:32:00.647", "1800-05-10 10:32:00.647"); + test(wrapper, "2024-09-09 20:26:14.841", "2024-09-09 20:26:14.841"); + } } catch (SQLException e) { @@ -260,5 +268,11 @@ public void testTimestamps() } } } + + private void test(TimestampStatementWrapper wrapper, String expected, String test) + { + Timestamp ts = Timestamp.valueOf(test); + Assert.assertEquals(expected, wrapper.convert(ts)); + } } } diff --git a/search/src/org/labkey/search/model/IndexInspector.java b/search/src/org/labkey/search/model/IndexInspector.java index 9c9dc4c9143..b9de8cdc5a2 100644 --- a/search/src/org/labkey/search/model/IndexInspector.java +++ b/search/src/org/labkey/search/model/IndexInspector.java @@ -152,7 +152,7 @@ protected int writeBody() if (titles.length != 1 || urls.length != 1 || uniqueIds.length != 1 || containerIds.length != 1) { - // Skip the special "serverGuid" doc + // Skip the special "server GUID" doc if (doc.get(LuceneSearchServiceImpl.SERVER_GUID_NAME) != null) continue;