7

我在 mysql 中有一个查询,它比较像这样的 2 个日期

convert_tz(updatedDate,'+05:30','-05:00') < ?

convert 函数以美国时间返回列 createddate 的值。当我在 mysql 查询浏览器中运行此查询时

convert_tz(updatedDate,'+05:30','-05:00') < '2013-04-14 09:30:00'

例如,它给了我正确的值

product    count
-------    ------
    A        123
    B        7

现在,我正在使用这样的 PreparedStatement 在 java 中设置它

pst.setTimestamp(1, new java.sql.Timestamp(end.getTimeInMillis()));

                rs=pst.executeQuery();
                System.out.println("=====new Open Tickets Query executed=====");
                System.out.println(pst);

最后一行打印整个查询,设置的值为

convert_tz(updatedDate,'+05:30','-05:00') < '2013-04-14 09:30:00'

但它给了我这样不同的价值观

product    count
-------    ------
    A        155
    B        19

所以,我怀疑是时区问题我将代码更改为

end.setTimeZone(TimeZone.getTimeZone("America/New York"));
pst.setTimestamp(1, new java.sql.Timestamp(end.getTimeInMillis()));

                rs=pst.executeQuery();
                System.out.println("=====new Open Tickets Query executed=====");
                System.out.println(pst);

但它仍然给出相同的错误结果。

更多信息:我如何设置日历结束变量

我有一个 Web 应用程序,它给了我日期字符串“2013-04-14 09:30:00”

            DateFormat df1=new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");
                Calendar end=Calendar.getInstance();
                end.setTime(df1.parse(endString));
                end.set(Calendar.HOUR, 9);
                end.set(Calendar.MINUTE, 30);
                end.set(Calendar.SECOND, 0);

另外,对于我尝试使用 java.util.Date 对象的实验,它给了我正确的结果,下面是代码

SimpleDateFormat sdf=new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");
end.setTime(sdf.parse("2012-10-01 00:00:00"));
pst.setTimestamp(1, new java.sql.Timestamp(end.getTime()));

更新:- 如果我使用不推荐使用的方法,答案是正确的

 pst.setTimestamp(1, new java.sql.Timestamp(octDate.get(Calendar.YEAR)-1900,octDate.get(Calendar.MONTH),octDate.get(Calendar.DATE),octDate.get(Calendar.HOUR),octDate.get(Calendar.MINUTE),octDate.get(Calendar.SECOND),0));
pst.setTimestamp(2, new java.sql.Timestamp(end.get(Calendar.YEAR)-1900,end.get(Calendar.MONTH),end.get(Calendar.DATE),end.get(Calendar.HOUR),end.get(Calendar.MINUTE),end.get(Calendar.SECOND),0));

更新2: - 在第一个答案的建议之后,我这样做了

1)SELECT NOW()在mysql中执行并返回'2013-04-22 11:56:08'

2) 执行

System.out.println(new Date(System.currentTimeMillis()));

输出 :Mon Apr 22 11:56:25 IST 2013

意味着两个系统具有相同的时区

4

5 回答 5

6

背景:即使是杰出的程序员也有一个令人惊讶的普遍且严重的误解,即存储时间戳(在您的数据库中,日期、日历、时间戳等)以某种方式具有时区信息。他们不。 时间戳(无论如何,直到 Java 8)存储为自 1970 年 1 月 1 日 UTC 午夜以来的毫秒数。句末。设置时区唯一要做的就是向计算机提供足够的信息,以将该时间戳转换为人类可读的格式,反之亦然。

答:当您怀疑这是时区问题时,您是对的。但是您用来验证这一点的代码也有问题:

end.setTimeZone(TimeZone.getTimeZone("America/New York"));
pst.setTimestamp(1, new java.sql.Timestamp(end.getTimeInMillis()));

setTimeZone语句对存储在 中的时间没有影响end,因为时间已经设置好了。只有在您之后存储时间,并且只有当您使用 Calendar 的一种方法将时间从人类可读格式(而不是 )转换时,它才会产生效果setTimeInMillis

当您使用getTimeInMillis将时间戳传递给准备好的语句时,您将直接检索时间戳。由于您没有将其转换为人类格式,因此时区信息再次被忽略。

当你尝试

SimpleDateFormat sdf=new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");
end.setTime(sdf.parse("2012-10-01 00:00:00"));
pst.setTimestamp(1, new java.sql.Timestamp(end.getTime()));

pst.setTimestamp(1, new java.sql.Timestamp(octDate.get(Calendar.YEAR)-1900,octDate.get(Calendar.MONTH),octDate.get(Calendar.DATE),octDate.get(Calendar.HOUR),octDate.get(Calendar.MINUTE),octDate.get(Calendar.SECOND),0));
pst.setTimestamp(2, new java.sql.Timestamp(end.get(Calendar.YEAR)-1900,end.get(Calendar.MONTH),end.get(Calendar.DATE),end.get(Calendar.HOUR),end.get(Calendar.MINUTE),end.get(Calendar.SECOND),0));

事情似乎有效,因为您现在正在使用与人类可读格式进行转换的方法,因此使用了指定的时区信息。然而,这只是掩盖了真正的问题。真正的问题是,当您从endString. 也就是说,表示的时区与解析日期时endString设置的时区不匹配。df1

简短答案:在此行之前:

end.setTime(df1.parse(endString));

你需要:

  • 找出endString表示时间的时区。
  • 设置df1不是 end同一时区。因为df1是将日期从人类格式转换的东西,所以使用的是时区信息。

干杯!

于 2013-04-26T23:12:25.473 回答
2

TimeZone.getDefault().getID()从您的和 MySQL 默认时区返回哪个值?

顺便说一句,您可以尝试使用像这样的实用程序来跨时区转换日期时间:

public Calendar convertDateToServerTimeZone(Date dateTime, String timeZone) {
    Calendar userDefinedTime = Calendar.getInstance();
    userDefinedTime.setTime(dateTime);
    if(!TimeZone.getDefault().getID().equalsIgnoreCase(timeZone)) {
    System.out.println        ("original defined time: " + userDefinedTime.getTime().toString() + " on tz:" + timeZone);
    Calendar quartzStartDate = new GregorianCalendar(TimeZone.getTimeZone(timeZone));
    quartzStartDate.set(Calendar.YEAR, userDefinedTime.get(Calendar.YEAR));
    quartzStartDate.set(Calendar.MONTH, userDefinedTime.get(Calendar.MONTH));
    quartzStartDate.set(Calendar.DAY_OF_MONTH, userDefinedTime.get(Calendar.DAY_OF_MONTH));
    quartzStartDate.set(Calendar.HOUR_OF_DAY, userDefinedTime.get(Calendar.HOUR_OF_DAY));
    quartzStartDate.set(Calendar.MINUTE, userDefinedTime.get(Calendar.MINUTE));
    quartzStartDate.set(Calendar.SECOND, userDefinedTime.get(Calendar.SECOND));
    quartzStartDate.set(Calendar.MILLISECOND, userDefinedTime.get(Calendar.MILLISECOND));
    System.out.println("adapted time for " + TimeZone.getDefault().getID() + ": " + quartzStartDate.getTime().toString());
    return quartzStartDate;
    } else {
    return userDefinedTime;
    }
}

我在这里使用过这个功能:Java Quartz-Scheduler across TimeZone

希望他的帮助。

于 2013-04-22T05:17:13.467 回答
1

如果没有看到第二个查询而不是第一个查询匹配的值,很难绝对确定。但要记住的一件事是,时区与偏移量不同。请阅读TimeZone 标签 wiki的“TimeZone != Offset”部分。

例如,您说您正在转换到America/New_York时区。该时区有时位于 UTC-05:00(东部标准时间),有时位于 UTC-04:00(东部夏令时间)。由于在夏令时有效的 -4 偏移量,您的某些数据完全有可能被拾取。

当您硬编码到 -5 偏移量时,您没有考虑任何时区规则。这可以解释这种差异。

于 2013-04-25T14:25:43.837 回答
1

时区信息不适用于日期/时间,除非您在连接 URL 中设置useTimeZone=true。您也可以使用getTimestamp()方法,它将日历作为参数。

于 2013-04-25T14:42:02.330 回答
1

试试这个。

按照您现在设置的方式设置时间戳参数

pst.setTimestamp(1, new java.sql.Timestamp(end.getTimeInMillis()));

.

在数据库调用期间,JDBC 驱动程序可能已经将输入日期/时间值转换为 GMT。因此,数据库正在处理的日期值不必考虑输入日期的时区,这可能因客户端而异。

而不是将from_tz设置为 '+05:30'

convert_tz(updatedDate,'+05:30','-05:00')

from_tz设置为 '00:00'

convert_tz(updatedDate,'00:00','-05:00') 
于 2013-04-27T17:20:02.477 回答