我在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
现在,我在java中使用PreparedStatement设置它,像这样
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)在mysql中执行SELECT NOW()
,它返回'2013-04-22 11:56:08'
System.out.println(new Date(System.currentTimeMillis()));
输出:Mon Apr 22 11:56:25 IST 2013
表示两个系统具有相同的时区
背景:即使是杰出的程序员也会有一个令人惊讶的常见误解,即存储的时间戳(在您的数据库中,Date, Calendar, Timestamp等)以某种方式具有时区信息。它们不需要。时间戳(无论如何,直到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));
things 看起来可以工作,因为您现在使用的是与人类可读格式进行转换的方法,因此使用了指定的时区信息。然而,这只是掩盖了真正的问题。真正的问题是,当您从endString
解析时间时,时间转换不正确。也就是说,表示endString
的时区与解析日期时df1
中设置的时区不匹配。
简短回答:在这行之前:
end.setTime(df1.parse(endString));
你需要:
- 找出
endString
中的时间是用哪个时区表示的 - 设置
df1
和不end
为同一时区。由于df1
是从人类格式转换日期的东西,因此使用的是时区信息。
干杯!
从您的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跨时区
希望他有帮助。
如果没有看到第二个查询匹配的值而不是第一个查询匹配的值,就很难绝对确定。但要记住的一件事是,时区与偏移量不同。请阅读TimeZone标签wiki的"TimeZone != Offset"部分。
例如,您说要转换为America/New_York
时区。这个区域有时是UTC-05:00(东部标准时间),有时是UTC-04:00(东部夏令时)。您的某些数据完全有可能因为夏令时-4偏移量而被拾取。
当您硬编码到-5偏移量时,您没有考虑任何时区规则。这就解释了这种差异。
时区信息不应用于日期/时间,除非您在连接URL中设置useTimeZone=true。您还可以使用getTimestamp()方法,它将日历作为参数。
给这个一试。
设置时间戳参数
pst.setTimestamp(1, new java.sql.Timestamp(end.getTimeInMillis()));
.
在数据库调用期间,JDBC驱动程序可能已经将输入的日期/时间值转换为GMT。因此,数据库处理的日期值不必考虑输入日期的时区,因为时区可能因客户机而异。
代替将from_tz设置为'+05:30'
convert_tz(updatedDate,'+05:30','-05:00')
Set from_tz为'00:00'
convert_tz(updatedDate,'00:00','-05:00')