Несоответствие часового пояса в mysql и java
у меня есть запрос в mysql, который сравнивает 2 даты, как это
convert_tz(updatedDate,'+05:30','-05:00') < ?
функция convert возвращает значение столбца createddate в US Time. когда я запускаю этот запрос в браузере запросов 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);
последняя строка печатает весь запрос и набор значений is
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);
но это все равно дает тот же неверный результат.
дополнительная информация: как я устанавливаю переменную конца календаря
у меня есть веб-приложение, которое дает мне строку даты "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.утиль.Дата объект он дает мне правильный результат, следующий код
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
означает, что обе системы имеют одинаковый часовой пояс
5 ответов
фон: удивительно распространенным-и большим-заблуждением, разделяемым даже блестящими программистами, является представление о том, что сохраненные метки времени (в вашей базе данных, дате, календаре, метке времени и т. д.) каким-то образом имеют информацию о часовом поясе. у них нет. метка времени (до Java 8, во всяком случае) хранится как количество миллисекунд с полуночи 1 января 1970 UTC. Конец предложения. Единственное, что делает настройка часового пояса, - это предоставить компьютеру достаточно информации для преобразования отметка времени в удобочитаемом формате, и наоборот.
ответ: когда вы подозревали, что это проблема часового пояса,ты был прав. Но код, который вы использовали для проверки этого, также имеет проблему:
end.setTimeZone(TimeZone.getTimeZone("America/New York"));
pst.setTimestamp(1, new java.sql.Timestamp(end.getTimeInMillis()));
это setTimeZone
заявление нет эффекта на время, хранящееся в end
, потому что время уже установлено. Это имело бы эффект, только если бы вы сохранили время после этого, и только если бы вы использовали один из Методы календаря, которые преобразовали время из читаемого человеком формата (а не 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
высказал в. - Set
df1
и неend
в тот же часовой пояс. Сdf1
это то, что преобразует дату из человеческого формата, это информация о часовом поясе, которая используется.
Ура!
какое значение возвращается из своего TimeZone.getDefault().getID()
и из часового пояса MySQL по умолчанию?
BTW вы можете попробовать использовать такую утилиту, как эта, чтобы конвертировать datetime через часовые пояса:
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-планировщик по часовому поясу
надеюсь его помощь.
Не видя значений, которые совпадают во втором запросе, а не в первом, трудно быть абсолютно уверенным. Но следует иметь в виду, что часовой пояс-это не то же самое, что смещение. Пожалуйста, прочитайте "часовой пояс != Смещение " раздел тег часового пояса wiki.
например, вы говорите, что преобразование America/New_York
часовой пояс. Эта зона иногда находится в UTC-05: 00 (для Восточного стандартного времени), а иногда в UTC-04:00 (для Восточного дневного света Время.) Вполне возможно, что некоторые из ваших данных собираются из-за смещения -4, действующего в летнее время.
когда вы жестко кодируете смещение -5, вы не принимаете во внимание правила часового пояса. Что объясняет расхождение.
информация о часовом поясе не применяется к датам / времени, если вы не установите useTimeZone=true в URL-адресе подключения. Вы можете использовать getTimestamp() метод также, которые принимают календари в качестве аргумента.
попробуйте.
установить параметр timestamp, как вы устанавливаете сейчас
pst.setTimestamp(1, new java.sql.Timestamp(end.getTimeInMillis()));
.
во время вызова базы данных драйвер JDBC может уже преобразовывать входные значения даты/времени в GMT. Таким образом, значение даты, с которым имеет дело база данных, не будет учитывать часовые пояса входной даты в соображениях, которые могут отличаться от одного клиента к другому.
вместо from_tz as '+05:30'
convert_tz(updatedDate,'+05:30','-05:00')
Set from_tz как '00:00'
convert_tz(updatedDate,'00:00','-05:00')