Java日历和时间UTC到BST



我得到一个格式为yyyy-MM-dd HH:MM的字符串,它表示UTC中的日期和时间。下一步是将其放入日历中(时区为UTC)。

此外,还需要创建一个单独的日历,将UTC转换为"欧洲/伦敦"时区(GMT/BST)。

之后,我需要能够检测"欧洲/伦敦"日历是否有夏令时(Day Light Savings Offset)。

下面的代码将显示我已经走了多远,它在默认系统时区为GMT的英国计算机上运行正常。但是,当我在时区为UTC的计算机上运行它时,它会失败。它似乎无法告诉我是否存在DST_偏移(始终为零)。

Calendar cal = Calendar.getInstance(TimeZone.getTimeZone("UTC"));
cal.set(Calendar.YEAR, 2016);
cal.set(Calendar.MONTH, 1);
cal.set(Calendar.DAY_OF_MONTH, 27);
cal.set(Calendar.HOUR_OF_DAY, 23);
cal.set(Calendar.MINUTE, 35);
cal.set(Calendar.SECOND, 0);
cal.set(Calendar.MILLISECOND, 0);
//This is required as Java Date JAN starts at 0.
int MonthCon = cal.get(Calendar.MONTH)-1;
cal.set(Calendar.MONTH, MonthCon);
Date d = cal.getTime();

SimpleDateFormat f = new SimpleDateFormat("yyyy-MM-dd HH:mm:ssz");
f.setTimeZone(TimeZone.getTimeZone("UTC"));
System.out.println("UTC:    " + f.format(d));
f.setTimeZone(TimeZone.getTimeZone("Europe/London"));
System.out.println("BST:    " + f.format(d));
//Creates a BST calendar of the same UTC time
String dateStrBST = f.format(d);
SimpleDateFormat curFormater = new SimpleDateFormat("yyyy-MM-dd HH:mm:ssz");
curFormater.setTimeZone(TimeZone.getTimeZone("Europe/London"));
Date dateObjBST = curFormater.parse(dateStrBST);

System.out.println("BSTNewDate:    " + f.format(dateObjBST));

Calendar calBST = Calendar.getInstance(TimeZone.getTimeZone("BST"));
calBST.setTime(dateObjBST);
System.out.println("Current TimeZone is : " +  calBST.getTimeZone());
int offset = calBST.get(Calendar.DST_OFFSET);
System.out.println("Day Light Savings: "+offset);
System.out.println("Transition Day: "+isDSTTransitionDay(cal.get(Calendar.YEAR),cal.get(Calendar.MONTH),cal.get(Calendar.DAY_OF_MONTH))+"   Transition Type: "+DSTtransitionType(cal.get(Calendar.YEAR),cal.get(Calendar.MONTH),cal.get(Calendar.DAY_OF_MONTH)));

不幸的是,我需要能够检测是否有任何特定的一天是过渡日,也就是说,从夏令时开启/关闭或关闭/开启开始的一天。这同样适用于本地计算机,但不适用于UTC时区一。

private static boolean isDSTTransitionDay(int year, int month, int day) throws ParseException
{
Calendar calStartofDay = Calendar.getInstance(TimeZone.getTimeZone("UTC"));
calStartofDay.set(Calendar.YEAR, year);
calStartofDay.set(Calendar.MONTH, month);
calStartofDay.set(Calendar.DAY_OF_MONTH, day);
calStartofDay.set(Calendar.HOUR_OF_DAY, 00);
calStartofDay.set(Calendar.MINUTE, 0);
calStartofDay.set(Calendar.SECOND, 1);            
Date dStartofDay = calStartofDay.getTime();            
SimpleDateFormat f = new SimpleDateFormat("yyyy-MM-dd HH:mm:ssz");                        
f.setTimeZone(TimeZone.getTimeZone("Europe/London"));            
String dateStrUTCtoBST = f.format(dStartofDay);

SimpleDateFormat curFormater = new SimpleDateFormat("yyyy-MM-dd HH:mm:ssz");
curFormater.setTimeZone(TimeZone.getTimeZone("Europe/London"));
Date dateObjBST = curFormater.parse(dateStrUTCtoBST);
Calendar calBST = Calendar.getInstance();
calBST.setTime(dateObjBST);            
int offsetStart = calBST.get(Calendar.DST_OFFSET);
calBST.add(Calendar.HOUR_OF_DAY, 23);
int offsetEnd = calBST.get(Calendar.DST_OFFSET);
//System.out.println("Start: "+offsetStart+" End: "+offsetEnd);


if (offsetEnd == offsetStart) 
{
return false;
}else
{
//if(offsetStart<offsetEnd) {System.out.println("Transition to BST");}else{System.out.println("Transition to UTC/GMT");};
return true;
}
}

因此,在UTC计算机上,它失败得很惨,因为它总是将Calendar.DST_OFFSET设置为零。在这一过程中,我显然误解了一些事情,所以任何帮助/澄清都是好的。

我几乎不得不保留Calendar,因为其他代码都在使用它,但我意识到Java8有很多更奇特的方式。

请允许我说实话,我试着阅读了你的代码,但并没有真正理解你试图获得你想要的东西的方式。如果您可以使用Java8,我建议您改用Java8日期和时间类。有了这些,你的工作就不那么复杂了。对于我选择的去年10月30日的示威活动,英国(和欧盟)从夏令时(夏令时)改回标准时间。

String originalDate = "2016-10-30 23:35";
LocalDateTime localTime = LocalDateTime.parse(originalDate, DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm"));
ZonedDateTime utcTime = localTime.atZone(ZoneOffset.UTC);
ZonedDateTime bstTime = utcTime.withZoneSameInstant(ZoneId.of("Europe/London"));
// the summer time offset is how many milliseconds?
long dstOffset = ChronoUnit.MILLIS.between(utcTime.toLocalDateTime(), bstTime.toLocalDateTime());
System.out.println(dstOffset); // prints 0
// try the same at start of day (midnight)
utcTime = utcTime.toLocalDate().atStartOfDay(ZoneOffset.UTC);
bstTime = utcTime.withZoneSameInstant(ZoneId.of("Europe/London"));
dstOffset = ChronoUnit.MILLIS.between(utcTime.toLocalDateTime(), bstTime.toLocalDateTime());
System.out.println(dstOffset); // prints 3600000
// and next midnight
utcTime = utcTime.plusDays(1);
bstTime = utcTime.withZoneSameInstant(ZoneId.of("Europe/London"));
dstOffset = ChronoUnit.MILLIS.between(utcTime.toLocalDateTime(), bstTime.toLocalDateTime());
System.out.println(dstOffset); // prints 0

您正在使用

Calendar calBST = Calendar.getInstance();

这将calBST设置为计算机的时区(在UTC计算机上,它将是UTC)。

calBST.setTime(dateObjBST);设置时间,而不是时区。

也可以尝试使用getInstance(TimeZone zone)


无论如何,我都会这样替换你的代码:

Calendar calStartofDay = Calendar.getInstance(TimeZone.getTimeZone("UTC"));
calStartofDay.set(Calendar.YEAR, 2017);
calStartofDay.set(Calendar.MONTH, 0);
calStartofDay.set(Calendar.DAY_OF_MONTH, 21);
calStartofDay.set(Calendar.HOUR_OF_DAY, 00);
calStartofDay.set(Calendar.MINUTE, 0);
calStartofDay.set(Calendar.SECOND, 1);            
Calendar calBST = Calendar.getInstance(TimeZone.getTimeZone("Europe/London"));
calBST.setTimeInMillis(calStartofDay.getTimeInMillis());
// use this to check the time
System.out.printf("%tc%n", calBST);

此外,从日历文档中,要小心这一点:

set(f,value)将日历字段f更改为value。此外,它设置内部成员变量,用于指示日历字段f已已更改。尽管日历字段f被立即更改日历的时间值(以毫秒为单位)直到下一个调用get()、getTime()、getTimeInMillis()、add()或roll()。因此,对set()的多次调用不会触发多次不必要的调用计算。作为使用set()更改日历字段的结果,其他日历字段也可能更改,具体取决于日历字段、日历字段值和日历系统。此外get(f)不一定会返回由对集合的调用所设置的值方法。具体情况由具体日历类确定。

相关内容

  • 没有找到相关文章

最新更新