TimeZone在mysql和java中的差异

时间:2013-04-18 07:24:15

标签: java mysql timezone convert-tz

我在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

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

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);

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

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

我有一个网络应用程序,它给我日期字符串“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)在mysql中执行SELECT NOW()并返回'2013-04-22 11:56:08'

2)执行

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

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

表示两个系统都有相同的时区

5 个答案:

答案 0 :(得分:6)

背景:即使是出色的程序员也有一个令人惊讶的常见和大错误概念,即存储时间戳(在您的数据库中,日期,日历,时间戳等)以某种方式具有时区信息。 他们没有。时间戳(直到Java 8,无论如何)被存储为自1970年1月1日午夜起的毫秒数。句末。设置时区的唯一方法是向计算机提供足够的信息,以将时间戳转换为人类可读的格式,反之亦然。

答案:如果您怀疑这是时区问题,您是对的。但是您用来尝试验证此代码的代码也存在问题:

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是从人格式转换日期的东西,因此它是使用的时区信息。

干杯!

答案 1 :(得分: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

希望他的帮助。

答案 2 :(得分:1)

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

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

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

答案 3 :(得分:1)

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

答案 4 :(得分:1)

试一试。

在设置时设置时间戳参数

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

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

而不是将 from_tz 设置为&#39; +05:30&#39;

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

from_tz 设为&#39; 00:00&#39;

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