JodaOrg / joda-time

Joda-Time is the widely used replacement for the Java date and time classes prior to Java SE 8.
http://www.joda.org/joda-time/
Apache License 2.0
4.98k stars 985 forks source link

Issue Parsing ID 'GMT+10:00' in DateTimeZone.java #782

Closed pceimpulsive closed 6 months ago

pceimpulsive commented 6 months ago

In the unlikely event you still think you've found an issue, please delete the text above and describe the problem as follows:

Key information

Problem description

Our Splunk system default timezone is GMT+10:00 A JDBC Driver implement Joda Time and passes this value into the forID Method at https://github.com/JodaOrg/joda-time/blob/main/src/main/java/org/joda/time/DateTimeZone.java#L231

The If Block at the below location resolves to True and the value of idToParse is '10:00' https://github.com/JodaOrg/joda-time/blob/main/src/main/java/org/joda/time/DateTimeZone.java#L249

The next line of code that is valid is the exception on L263 as the output of 'id.substring(3);' has no +/- as the first character.

https://github.com/JodaOrg/joda-time/blob/main/src/main/java/org/joda/time/DateTimeZone.java#L263

To me this isn't a terribly complicated fix to support this string format

Something like the following else if might work?


if (idToParse.startsWith("+") || idToParse.startsWith("-")) {
    int offset = parseOffset(idToParse);
    if (offset == 0L) {
        return DateTimeZone.UTC;
    } else {
        idToParse = printOffset(offset);
        return fixedOffsetZone(idToParse, offset);
    }
} else if (Character.isDigit(idToParse.charAt(0)) && idToParse.contains(":")) {
    // Remove the colon from the string before calling parseOffset
    String idWithoutColon = idToParse.replace(":", "");
    int offset = parseOffset(idWithoutColon);

    if (offset == 0L) {
        return DateTimeZone.UTC;
    } else {
        idToParse = printOffset(offset);
        return fixedOffsetZone(idToParse, offset);
    }
}

Test case

~ I am not a Java developer sorry i can't really test this.. here is the error i'm getting with Splunk DBXConnect using a Trino JDBC driver that implements the Joda library.

Error Messaging >>

2024-05-08 12:02:52.798 +1000  [dw-60 - POST /api/connections/status] INFO  com.splunk.dbx.connector.logger.AuditLogger - operation= connection_name= stanza_name= state=error sql='select version()' message='Error executing query: The datetime zone id 'GMT+10:00' is not recognised'
2024-05-08 12:02:52.799 +1000  [dw-60 - POST /api/connections/status] ERROR c.s.dbx.connector.connector.impl.JdbcConnectorImpl - action=error_in_validating_connection_with_customized_test_query cause=Error executing query: The datetime zone id 'GMT+10:00' is not recognised
java.sql.SQLException: Error executing query: The datetime zone id 'GMT+10:00' is not recognised
        at io.trino.jdbc.TrinoStatement.internalExecute(TrinoStatement.java:287)
        at io.trino.jdbc.TrinoStatement.execute(TrinoStatement.java:240)
        at io.trino.jdbc.TrinoPreparedStatement.<init>(TrinoPreparedStatement.java:121)
        at io.trino.jdbc.TrinoConnection.prepareStatement(TrinoConnection.java:174)
        at com.splunk.dbx.connector.connector.impl.JdbcConnectorImpl.executeQuery(JdbcConnectorImpl.java:279)
        at com.splunk.dbx.connector.connector.impl.JdbcConnectorImpl.isValid(JdbcConnectorImpl.java:158)
        at com.splunk.dbx.server.api.service.database.impl.DatabaseMetadataServiceImpl.isConnectionValid(DatabaseMetadataServiceImpl.java:167)
        at com.splunk.dbx.server.api.service.database.impl.DatabaseMetadataServiceImpl.getStatus(DatabaseMetadataServiceImpl.java:139)
        at com.splunk.dbx.server.api.service.database.impl.DatabaseMetadataServiceImpl.getConnectionStatus(DatabaseMetadataServiceImpl.java:116)
        at com.splunk.dbx.server.api.resource.ConnectionResource.getConnectionStatusOfEntity(ConnectionResource.java:72)
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
        at java.lang.reflect.Method.invoke(Method.java:498)
        at org.glassfish.jersey.server.model.internal.ResourceMethodInvocationHandlerFactory.lambda$static$0(ResourceMethodInvocationHandlerFactory.java:52)
        at org.glassfish.jersey.server.model.internal.AbstractJavaResourceMethodDispatcher$1.run(AbstractJavaResourceMethodDispatcher.java:124)
        at org.glassfish.jersey.server.model.internal.AbstractJavaResourceMethodDispatcher.invoke(AbstractJavaResourceMethodDispatcher.java:167)
        at org.glassfish.jersey.server.model.internal.JavaResourceMethodDispatcherProvider$TypeOutInvoker.doDispatch(JavaResourceMethodDispatcherProvider.java:219)
        at org.glassfish.jersey.server.model.internal.AbstractJavaResourceMethodDispatcher.dispatch(AbstractJavaResourceMethodDispatcher.java:79)
        at org.glassfish.jersey.server.model.ResourceMethodInvoker.invoke(ResourceMethodInvoker.java:469)
        at org.glassfish.jersey.server.model.ResourceMethodInvoker.apply(ResourceMethodInvoker.java:391)
        at org.glassfish.jersey.server.model.ResourceMethodInvoker.apply(ResourceMethodInvoker.java:80)
        at org.glassfish.jersey.server.ServerRuntime$1.run(ServerRuntime.java:253)
        at org.glassfish.jersey.internal.Errors$1.call(Errors.java:248)
        at org.glassfish.jersey.internal.Errors$1.call(Errors.java:244)
        at org.glassfish.jersey.internal.Errors.process(Errors.java:292)
        at org.glassfish.jersey.internal.Errors.process(Errors.java:274)
        at org.glassfish.jersey.internal.Errors.process(Errors.java:244)
        at org.glassfish.jersey.process.internal.RequestScope.runInScope(RequestScope.java:265)
        at org.glassfish.jersey.server.ServerRuntime.process(ServerRuntime.java:232)
        at org.glassfish.jersey.server.ApplicationHandler.handle(ApplicationHandler.java:680)
        at org.glassfish.jersey.servlet.WebComponent.serviceImpl(WebComponent.java:394)
        at org.glassfish.jersey.servlet.WebComponent.service(WebComponent.java:346)
        at org.glassfish.jersey.servlet.ServletContainer.service(ServletContainer.java:366)
        at org.glassfish.jersey.servlet.ServletContainer.service(ServletContainer.java:319)
        at org.glassfish.jersey.servlet.ServletContainer.service(ServletContainer.java:205)
        at io.dropwizard.jetty.NonblockingServletHolder.handle(NonblockingServletHolder.java:50)
        at org.eclipse.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1651)
        at io.dropwizard.servlets.ThreadNameFilter.doFilter(ThreadNameFilter.java:35)
        at org.eclipse.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1638)
        at io.dropwizard.jersey.filter.AllowedMethodsFilter.handle(AllowedMethodsFilter.java:47)
        at io.dropwizard.jersey.filter.AllowedMethodsFilter.doFilter(AllowedMethodsFilter.java:41)
        at org.eclipse.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1638)
        at com.splunk.dbx.server.api.filter.ResponseHeaderFilter.doFilter(ResponseHeaderFilter.java:30)
        at org.eclipse.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1638)
        at org.eclipse.jetty.servlet.ServletHandler.doHandle(ServletHandler.java:567)
        at org.eclipse.jetty.server.handler.ScopedHandler.nextHandle(ScopedHandler.java:233)
        at org.eclipse.jetty.server.handler.ContextHandler.doHandle(ContextHandler.java:1377)
        at org.eclipse.jetty.server.handler.ScopedHandler.nextScope(ScopedHandler.java:188)
        at org.eclipse.jetty.servlet.ServletHandler.doScope(ServletHandler.java:507)
        at org.eclipse.jetty.server.handler.ScopedHandler.nextScope(ScopedHandler.java:186)
        at org.eclipse.jetty.server.handler.ContextHandler.doScope(ContextHandler.java:1292)
        at org.eclipse.jetty.server.handler.ScopedHandler.handle(ScopedHandler.java:141)
        at org.eclipse.jetty.server.handler.HandlerWrapper.handle(HandlerWrapper.java:127)
        at com.codahale.metrics.jetty9.InstrumentedHandler.handle(InstrumentedHandler.java:249)
        at io.dropwizard.jetty.RoutingHandler.handle(RoutingHandler.java:52)
        at org.eclipse.jetty.server.handler.gzip.GzipHandler.handle(GzipHandler.java:717)
        at org.eclipse.jetty.server.handler.RequestLogHandler.handle(RequestLogHandler.java:54)
        at org.eclipse.jetty.server.handler.StatisticsHandler.handle(StatisticsHandler.java:173)
        at org.eclipse.jetty.server.handler.HandlerWrapper.handle(HandlerWrapper.java:127)
        at org.eclipse.jetty.server.Server.handle(Server.java:501)
        at org.eclipse.jetty.server.HttpChannel.lambda$handle$1(HttpChannel.java:383)
        at org.eclipse.jetty.server.HttpChannel.dispatch(HttpChannel.java:556)
        at org.eclipse.jetty.server.HttpChannel.handle(HttpChannel.java:375)
        at org.eclipse.jetty.server.HttpConnection.onFillable(HttpConnection.java:273)
        at org.eclipse.jetty.io.AbstractConnection$ReadCallback.succeeded(AbstractConnection.java:311)
        at org.eclipse.jetty.io.FillInterest.fillable(FillInterest.java:105)
        at org.eclipse.jetty.io.ChannelEndPoint$1.run(ChannelEndPoint.java:104)
        at org.eclipse.jetty.util.thread.strategy.EatWhatYouKill.runTask(EatWhatYouKill.java:336)
        at org.eclipse.jetty.util.thread.strategy.EatWhatYouKill.doProduce(EatWhatYouKill.java:313)
        at org.eclipse.jetty.util.thread.strategy.EatWhatYouKill.tryProduce(EatWhatYouKill.java:171)
        at org.eclipse.jetty.util.thread.strategy.EatWhatYouKill.run(EatWhatYouKill.java:129)
        at org.eclipse.jetty.util.thread.ReservedThreadExecutor$ReservedThread.run(ReservedThreadExecutor.java:375)
        at org.eclipse.jetty.util.thread.QueuedThreadPool.runJob(QueuedThreadPool.java:806)
        at org.eclipse.jetty.util.thread.QueuedThreadPool$Runner.run(QueuedThreadPool.java:938)
        at java.lang.Thread.run(Thread.java:750)
Caused by: java.lang.IllegalArgumentException: The datetime zone id 'GMT+10:00' is not recognised
        at io.trino.jdbc.$internal.joda.time.DateTimeZone.forID(DateTimeZone.java:249)
        at io.trino.jdbc.AbstractTrinoResultSet.<init>(AbstractTrinoResultSet.java:196)
        at io.trino.jdbc.TrinoResultSet.<init>(TrinoResultSet.java:68)
        at io.trino.jdbc.TrinoResultSet.create(TrinoResultSet.java:62)
        at io.trino.jdbc.TrinoStatement.internalExecute(TrinoStatement.java:262)
        ... 75 common frames omitted
pceimpulsive commented 6 months ago

I derped on this one and mis-understood the substring(int) method in Java, The Joda Library looks fine, i'm closing the issue...

Splunk must be sending an additional character or non-white space character in the input string resulting in Joda throwing the exception~ as such it's a source system issue not the Joda zone parsing~

sorry... have a good day!

pceimpulsive commented 6 months ago

Note: I found through digging that the older version of Joda will be the reason for this issue i have reported. As such the issue is simply "My Splunk is using an old version of Joda.. I can see the latest release in last 2023 added the additional logic to support the timezone I was concerned with. I was on the right path, just a version too late :D haha..

My Issue was raised as mentioned at Line 249 of the older release version... https://github.com/JodaOrg/joda-time/commit/0e251d278604252a9986f2338c1cee56a9e052a2