通过jsp执行时SQL语句不给出本地时间

Posted

技术标签:

【中文标题】通过jsp执行时SQL语句不给出本地时间【英文标题】:SQL statement does not give local time when execute through jsp 【发布时间】:2014-10-19 22:14:30 【问题描述】:

当我从独立的 JDBC 程序对 SQLite JDBC 驱动程序执行 SQL 语句“SELECT datetime('now', 'localtime')”时,我得到正确的本地时间戳,而当我通过 JSP 页面执行它时,我得到格林威治标准时间/UTC 时间。有人可以解释为什么在 JSP 代码的情况下我会得到 UTC 时间吗?我想要由独立程序给出的当地时间。我确保两者都使用相同的 JDBC 驱动程序 jar 文件“sqlite-jdbc-3.7.2.jar”。

这是独立的 SQLite JDBC 程序:

import java.sql.*;

public class GetTimestamp

    public static void main(String[] args)
    
        Connection conn = null;
        PreparedStatement p = null;
        ResultSet rs = null;
        try 
            Class.forName("org.sqlite.JDBC"); 
            conn = DriverManager.getConnection("jdbc:sqlite:C:/sqlite/db1", null, null);
            p  = conn.prepareStatement("SELECT datetime('now', 'localtime')");
            rs = p.executeQuery();
            System.out.println("Current timestamp = " + rs.getString(1));
            conn.close();
         catch (SQLException se) 
            System.out.println("Error: " + se.toString());
         catch (ClassNotFoundException cnfe) 
            System.out.println("Error: " + cnfe.toString());
        
        

它的输出:

这是等效的 JSP:

<html>
<BODY>  
<%@page import="java.sql.*"%>
<%
    Connection conn = null;
    PreparedStatement p = null;
    ResultSet rs = null;
    try 
        Class.forName("org.sqlite.JDBC"); 
        conn = DriverManager.getConnection("jdbc:sqlite:C:/sqlite/db1", null, null);
        p  = conn.prepareStatement("SELECT datetime('now', 'localtime')");
        rs = p.executeQuery();
        //System.out.println("Current timestamp = " + rs.getString(1));
        out.println("Current timestamp = " + rs.getString(1));
        conn.close();
     catch (SQLException se) 
        //System.out.println("Error: " + se.toString());
        out.println("Error: " + se.toString());
     catch (ClassNotFoundException cnfe) 
        //System.out.println("Error: " + cnfe.toString());
        out.println("Error: " + cnfe.toString());
    
%>
</BODY>
</HTML

它的输出是

【问题讨论】:

出于对代码的热爱,总是在 finally 块中关闭您的 ResultSet、Statement/PreparedStatement 以及最后的 Connection。在 Java 6 及更高版本(在某些类上)可能不需要它,但它是最佳编程实践。 您是否尝试过使用rs.getDateSimpleDateFormat?正如你所拥有的那样,你依赖于太多可能的变量。 布哈克辛迪,感谢您的建议。我提到的代码只是为了演示问题,而不是最终代码的一部分,它将处理您提到的问题。 OldCurmudgeon,我需要时间戳,而不仅仅是日期。我尝试了以下方法 rs.geTring(1) 是最接近的方法,只是它没有给出与 GMT 偏移 5.30 的时间: rs.getDate(1).toString() = 1970-01-01 rs.getTime(1 ).toString() = 05:30:00 rs.getTimestamp(1).toString() = 1970-01-01 05:30:00.0 rs.getString(1) = 2014-08-27 05:18:06 你用的是什么版本的 SQLLite? 【参考方案1】:

您可能需要设置时区?胡思乱想,希望对您有所帮助...

<fmt:setTimeZone value="GMT+10" /> //Set to whatever your timezone is

我不确定这是否有帮助。

【讨论】:

【参考方案2】:

好吧,当我们在我们的脚本中使用隐式对象 out 时,它不会像 System.out 那样生成纯输出,因为它是 javax.servlet.jsp.JspWriter 的一种类型,所以它生成 HTML 而不是纯输出输出。

所以,有了这些信息,我假设这个对象正在以你不想要的方式包装你的信息。

您可能必须以另一种方式输出它,例如使用标签 setTimeZone 正如 Corey 所说,这是一个示例:

<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<%@ taglib uri="http://java.sun.com/jsp/jstl/fmt" prefix="fmt" %>
<html>
<head>
<title>JSTL fmt:setTimeZone Tag</title>
</head>
<body>
<c:set var="now" value="<%=new java.util.Date()%>" />
<p>Date in Current Zone: <fmt:formatDate value="$now" 
             type="both" timeStyle="long" dateStyle="long" /></p>
<p>Change Time Zone to GMT-8</p>
<fmt:setTimeZone value="GMT-8" />
<p>Date in Changed Zone: <fmt:formatDate value="$now" 
             type="both" timeStyle="long" dateStyle="long" /></p>
</body>
</html>

【讨论】:

Bruno,我将 String 对象传递给 out.println() 方法,因此该方法不太可能知道传递的 String 对象是否是时间戳/日期时间对象。我不在我的 JSP 页面中使用像“c:set”这样的标签。当我尝试您的代码时,没有值显示为部分

标记。为了使您的代码正常工作,我是否需要安装其他东西以及 Tomcat Web 服务器?

我正在寻找不使用 taglibs 的解决方案。一些建议使用 Tomcat 配置工具或直接编辑 windows 注册表为 Java 设置时区环境变量。但到目前为止还没有运气。【参考方案3】:

从我从这个thread 中读到的内容。 SQLLite 没有Date type,所以需要使用rs.getString(1);获取它的String

试试这个。

 <%
        Connection conn = null;
        PreparedStatement p = null;
        ResultSet rs = null;
        try 
            Class.forName("org.sqlite.JDBC"); 
            conn = DriverManager.getConnection("jdbc:sqlite:C:/sqlite/db1", null, null);
            p  = conn.prepareStatement("SELECT datetime('now', 'localtime')");
            rs = p.executeQuery();

            //System.out.println("Current timestamp = " + rs.getString(1));
            DateFormat converter = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
            Date queryDate = converter.parse(rs.getString(1));
            out.println("Current timestamp = " + converter.format(queryDate));

            conn.close();
         catch (SQLException se) 
            //System.out.println("Error: " + se.toString());
            out.println("Error: " + se.toString());
         catch (ClassNotFoundException cnfe) 
            //System.out.println("Error: " + cnfe.toString());
            out.println("Error: " + cnfe.toString());
        catch(ParseException e)
            out.println("ParseError: " + e.toString());
        
    %>

不确定这是否有帮助。

【讨论】:

只要对你有帮助就没有问题。【参考方案4】:

最后,我根据大家的意见想出了一个解决方法。基本上,它获取时区信息,获取其偏移量,将偏移量添加到从 SQLite 查询的时间戳值。 当然,当 SQLite JDBC 驱动程序将来开始提供正确的值时,变通方法会有一点危险!

<HTML>
<BODY>  
<%@page import="java.sql.*"%>
<%@page import="java.util.*"%>
<%@page import="java.text.*"%>
<%
    Connection conn = null;
    PreparedStatement p = null;
    ResultSet rs = null;

    // Get current timezone and find offset from UTC.
    TimeZone timeZone = TimeZone.getDefault();
    out.println("<BR>Current timezone=" + timeZone);
    long offset = timeZone.getOffset(System.currentTimeMillis());
    out.println("<BR>Timezone offset=" + offset);

    try 
        Class.forName("org.sqlite.JDBC"); 
        conn = DriverManager.getConnection("jdbc:sqlite:C:/sqlite/db1", null, null);
        p  = conn.prepareStatement("SELECT datetime('now', 'localtime')");
        rs = p.executeQuery();

        // Convert queried timestamp to Java Date object.
        DateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        java.util.Date queryDate = sdf.parse(rs.getString(1));
        out.println("<BR>timestamp from SQLite = " + sdf.format(queryDate));

        // Get localtime by adding time zone offset.
        long tm = queryDate.getTime() + offset; // New time with offset.
        java.util.Date newDate = new java.util.Date(tm);
        out.println("<BR>timestamp with timezone offset= " + sdf.format(newDate));

        rs.close();
        conn.close();
     catch (SQLException se) 
        //System.out.println("Error: " + se.toString());
        out.println("Error: " + se.toString());
     catch (ClassNotFoundException cnfe) 
        //System.out.println("Error: " + cnfe.toString());
        out.println("Error: " + cnfe.toString());
    

%>
</BODY>
</HTML>

这里是 o/p:

【讨论】:

以上是关于通过jsp执行时SQL语句不给出本地时间的主要内容,如果未能解决你的问题,请参考以下文章

SQL SERVER2008远程备份数据库到本地

Navicat for MySQL怎样执行SQL语句

shiro实现本地内存Ehcache实现将菜单权限进行缓存

Oracle - PLS-00642:SQL 语句中不允许本地集合类型

通过过程执行时 SQL 语句不起作用

通过SCCM 梳理计算机本地账号——SQL 语句梳理