Java夏令时的问题



我有一个Java应用程序,它需要识别时区。当我获取Unix epoch时间并尝试将其转换为用于Oracle SQL调用的时间戳时,它得到了正确的时区,但时区"useDaylightTime"值不正确,即,当我们不在夏令时时,它当前返回"true"(我在佛罗里达州,TZ为"America/New_York")。

这是在Red Hat Linux Enterprise 6上运行的,据我所知,它是为时区正确设置的,例如"date"返回:2012年11月28日星期三美国东部时间12:30:12

使用"zdump"实用程序,我还可以看到"isdst"的当前值为0。

我的Java版本是1.6.0_31。

我在谷歌上搜索了一下,看到了这导致的许多问题,但其中许多问题只是说手动设置TZ,但我的问题不是TZ,而是默认TZ的"isDaylight"设置为"true"。我相信这会导致我的查询返回一个小时的休息数据(我可以看出是这样)。

以下是我运行的一段简单代码,试图以最简单的方式复制它:

public class TZdefault {
public static void main(String[] args) throws IOException {
long startTime = System.currentTimeMillis()/1000;
Calendar start = Calendar.getInstance();
start.setTimeInMillis(startTime);
start.setTimeZone(TimeZone.getDefault());
System.out.println("Start UTC: " + start + "ms: " + start.getTimeInMillis());
System.out.println("use daylight: " + start.getTimeZone().useDaylightTime());
} // end main

}  // end class

最后一件事。如果在我的代码中,我将TZ设置为"EST",那么当然会返回一个"isDaylight"设置为False的TZ。但这不是一个好的解决方案。

我想补充一些我一直希望隐藏的细节。

我在Oracle 11g数据库中有使用TIMESTAMP和TIMEZONE字段的记录。我只是简单地执行JDBC查询,其中两个参数使用BETWEEN开始时间戳和结束时间戳。

当我查询这个表时,我使用的是一个准备好的语句,该语句使用的是Calendar条目,其唯一目的是尝试操作时区。底线是,我正在使用"getTimeInMillis"方法对应用"默认"时区后的开始和结束时间进行pstmt.setTimestamp()调用。日志输出显示,实际上它输入了正确的毫秒数,但返回的SQL结果显然正好偏离了一个小时!

我仍在努力验证数据插入方面是否也没有问题。

但是我有很多调试信息,看起来我在JDBC查询中要求正确的时间。

时区useDaylightTime值不正确,即当我们不在DST 时,它当前返回"true">

我认为您混淆了useDaylightTimeinDaylightTime。前者告诉你未来是否会在夏令时和标准时间之间转换,而不是你在转换的哪一边。例如,它对中国时区返回false,因为中国不会调整夏令时,但对美国大多数时区返回true,因为美国大多数州(亚利桑那州除外)都遵守夏令时。

inDaylightTime

public abstract boolean inDaylightTime(Date date)

查询给定日期是否在此时区的夏令时中。

useDaylightTime

public abstract boolean useDaylightTime()

查询此时区是否使用夏令时。如果基础时区实现子类支持历史和未来的夏令时时间表更改,则此方法引用最后一个已知的夏令时规则,该规则可以是未来预测,并且可能与当前规则不同。如果还应考虑当前规则,请考虑调用observesDaylightTime()

如果要禁用夏令时计算,则必须将时区设置为EST。否则,时间将根据为AMERICA/NEW_YORK 设置的默认时区计算

TimeZone zoneEST = TimeZone.getTimeZone("EST"); 
System.out.println(zoneEST.getDSTSavings());  //0 hour
System.out.println(zoneEST.getRawOffset());  //5 hour
TimeZone.setDefault(zoneEST);
System.out.println("");
TimeZone zoneNY = TimeZone.getTimeZone("America/New_York");
System.out.println(zoneNY.getDSTSavings()); // 1 hour
System.out.println(zoneNY.getRawOffset()); // 5 hour

我找到了一种方法来确保忽略夏令时

TimeZone tz = TimeZone.getTimeZone("GMT");
TimeZone.setDefault(tz);
GregorianCalendar calendar;
calendar = new GregorianCalendar();

在创建GregorianCalendar对象之前设置时区

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.TimeZone;
public class TimeZoneTest {
public static void main(String[] argv) throws ParseException {
SimpleDateFormat formatter = new SimpleDateFormat("dd-M-yyyy hh:mm:ss a");
String dateInString = "22-01-2015 10:15:55 AM";
Date date = formatter.parse(dateInString);
TimeZone tz = TimeZone.getDefault();
// From TimeZone Asia/Singapore
System.out.println("TimeZone : " + tz.getID() + " - " + tz.getDisplayName());
System.out.println("TimeZone : " + tz);
System.out.println("Date : " + formatter.format(date));
// To TimeZone America/New_York
SimpleDateFormat sdfAmerica = new SimpleDateFormat("dd-M-yyyy hh:mm:ss a");
TimeZone tzInAmerica = TimeZone.getTimeZone("America/New_York");
sdfAmerica.setTimeZone(tzInAmerica);
String sDateInAmerica = sdfAmerica.format(date); // Convert to String first
Date dateInAmerica = formatter.parse(sDateInAmerica);
System.out.println("nTimeZone : " + tzInAmerica.getID() + 
" - " + tzInAmerica.getDisplayName());
System.out.println("TimeZone : " + tzInAmerica);
System.out.println("Date (String) : " + sDateInAmerica);
System.out.println("Date (Object) : " + formatter.format(dateInAmerica)); 
}
}

相关内容

  • 没有找到相关文章

最新更新