我在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
表示两个系统都有相同的时区
答案 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')