TimeZone与日历令人困惑的结果 [英] TimeZone with Calendar confusing results

查看:136
本文介绍了TimeZone与日历令人困惑的结果的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我最近一直在处理时区转换,并且对我得到的结果感到非常惊讶。基本上,我希望将日期从一个时区转换为另一个时区。下面是代码,转换工作正常,但我在调试时观察到的是,除非我调用 Calendar#get(Calendar.FIELD),否则不会转换日期。

I have been working with timezone conversions lately and am quite astonished by the result i get.Basically, i want to convert a date from one timezone into another. below is the code, conversions working fine, but what i have observed while debugging is, the date is not converted unless i call Calendar#get(Calendar.FIELD).

    private static void convertTimeZone(String date, String time, TimeZone fromTimezone, TimeZone toTimeZone){
        Calendar cal = Calendar.getInstance(fromTimezone);
        String[] dateSplit = null;
        String[] timeSplit = null;
        if(time !=null){
            timeSplit = time.split(":");
        }
        if(date!=null){
            dateSplit = date.split("/");
        }
        if(dateSplit !=null){
            cal.set(Calendar.DATE, Integer.parseInt(dateSplit[0]));
            cal.set(Calendar.MONTH, Integer.parseInt(dateSplit[1])-1);
            cal.set(Calendar.YEAR, Integer.parseInt(dateSplit[2]));
        }
        if(timeSplit !=null){
            cal.set(Calendar.HOUR_OF_DAY, Integer.parseInt(timeSplit[0]));
            cal.set(Calendar.MINUTE, Integer.parseInt(timeSplit[1]));

        }
//      System.out.println("Time in " + fromTimezone.getDisplayName() + " : " + cal.get(Calendar.DATE) +"/"+ (cal.get(Calendar.MONTH)+1)+"/"+ cal.get(Calendar.YEAR) +" " + ((cal.get(Calendar.HOUR_OF_DAY)<10) ? ("0"+cal.get(Calendar.HOUR_OF_DAY) ): (cal.get(Calendar.HOUR_OF_DAY)))
//              +":" + (cal.get(Calendar.MINUTE)<10 ? "0"+cal.get(Calendar.MINUTE) : cal.get(Calendar.MINUTE)) );
        cal.setTimeZone(toTimeZone);
        System.out.println("Time in " + toTimeZone.getDisplayName() + " : " + cal.get(Calendar.DATE) +"/"+ (cal.get(Calendar.MONTH)+1)+"/"+ cal.get(Calendar.YEAR) +" " + ((cal.get(Calendar.HOUR_OF_DAY)<10) ? ("0"+cal.get(Calendar.HOUR_OF_DAY) ): (cal.get(Calendar.HOUR_OF_DAY)))
                +":" + (cal.get(Calendar.MINUTE)<10 ? "0"+cal.get(Calendar.MINUTE) : cal.get(Calendar.MINUTE)) );
}

public static void main(String[] args) throws ParseException {

        convertTimeZone("23/04/2013", "23:00", TimeZone.getTimeZone("EST5EDT"), TimeZone.getTimeZone("GB"));
    }

预期输出: 格林威治时间平均时间:2013年4月24日04:00

当我评论sysout 1时得到的输出: 格林威治时间平均时间:23/4/2013 23:00

如果我取消评论sysout1我得到了预期的有效输出。

If i un-comment sysout1 i get the expected valid output.

感谢任何帮助

推荐答案

给定的内部表示直到您真正需要时才会评估日期,直到您尝试通过这些getter访问它。然而,解析日期的最佳方法是通过SimpleDateFormat。

The internal representation of the given date is not evaluated until really needed, that is until you try to access it by those getters. However the best way of parsing dates is through SimpleDateFormat.

编辑(添加用于汇总下面的评论,以便更好地澄清我的答案)。

EDIT (added for summarize the comments below and to better clarify my answer).

日历以这种方式工作以提高效率:每次调用一个setter时它都会重新计算,它会等到你调用一个getter。

Calendar works this way for better efficiency: instead of recalculate everithing each time you call a setter, it waits until you call a getter.

日历应该主要用于日期计算(参见 add() roll() ),但是你正在使用它进行解析和格式化:使用SimpleDateFormat可以更好地完成这些任务,这就是为什么我说你对Calendar的使用并不优雅。

Calendar should be used mainly for date calculations (see add() and roll()), but you are using it for parsing and formatting: these tasks are better accomplished with SimpleDateFormat, that's why I say that your usage of Calendar is not elegant.

参见此示例:

private static void convertTimeZone(String date, String time,
            TimeZone fromTimezone, TimeZone toTimeZone) throws ParseException {
    SimpleDateFormat df = new SimpleDateFormat("dd/MM/yyyy HH:mm");
    df.setTimeZone(fromTimezone);
    Date d = df.parse(date + " " + time);
    df.setTimeZone(toTimeZone);
    System.out.println("Time in " + toTimeZone.getDisplayName() + " : " +
                       df.format(d));
}

我只使用SimpleDateFormat重新实现了你的方法。我的方法较小,没有拆分逻辑(它隐藏在 parse()中),并且输出也以更简单的方式处理。此外,日期格式以紧凑和标准的方式表示,可以使用ResourceBundle轻松实现国际化。

I have reimplemented your method using SimpleDateFormat only. My method is smaller, there is no splitting logic (it's hidden in parse()), and also the output is handled in a simpler way. Furthermore the date format is expressed in a compact and standard way that can be easily internationalized using a ResourceBundle.

另请注意,时区转换只是一个格式化任务:内部解析日期的表示形式更改。

Also note that the timezone conversion is just a formatting task: the internal representation of the parsed date does not change.

这篇关于TimeZone与日历令人困惑的结果的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆