请参阅以下代码:
String timeString = "1980-01-01T14:00:00+0300";
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssZ");
Date date2 = sdf.parse(timeString);
// sdf.getCalendar().get(Calendar.ZONE_OFFSET);
System.out.println(sdf.format(date2));
现在,我来自一个+2h
偏移,+1
夏令时(目前)的国家/地区。
如果我按原样运行此代码,它将打印
1980-01-01T13:00:00+0200
如果我取消注释询问日历偏移的行,则该程序的输出为
1980-01-01T14:00:00+0300
知道为什么会发生这种情况,我怎样才能获得一致的输出?
为了避免任何不清楚的事情: 由于我正在处理一些遗留代码,因此java 8不是一个选项。是的,这里的关键点是为什么,而不是解决方法是什么? 有2个为什么:
答案 0 :(得分:2)
问题是,Calendar#get
不是一个简单的getter,它看起来像这样:
public int get(int field)
{
complete();
return internalGet(field);
}
根据Javadoc,complete
执行此操作:
填写日历字段中的任何未设置字段。首先,如果尚未根据日历字段值计算时间值(距Epoch的毫秒偏移量),则调用
computeTime()
方法。然后,调用computeFields()
方法来计算所有日历字段值。
我查了源here,但最新的Java版本的代码也一样。
答案 1 :(得分:0)
sdf.parse
将格式化程序的内部日历区域偏移更改为+0300
System.out.println(sdf.getCalendar());
sdf.parse(timeString);
System.out.println(sdf.getCalendar());
你可以看到输出行末尾的差异
... ,ZONE_OFFSET=7200000,DST_OFFSET=0]
... ,ZONE_OFFSET=10800000,DST_OFFSET=0]
sdf.getCalendar().get(Calendar.ZONE_OFFSET);
将日历区域偏移恢复为当前时区
答案 2 :(得分:0)
SimpleDateFormate使用Calendar创建日期。使用时间戳创建日期对象,其中计算方式为java.util.GregorianCalendar.computeTime()
。在第2789行中使用了初始时区(已设置java.text.SimpleDateFormat.initializeCalendar(Locale)
)。这就是为什么你看到错误的时区。
当您致电get(Calendar.ZONE_OFFSET)
时,会调用方法java.util.GregorianCalendar.computeFields()
,该方法使用最初设置的时区。
我猜这是一个Bug。