TimeZone with Calendar confusing results

前端 未结 5 2066
情深已故
情深已故 2021-01-06 06:19

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

相关标签:
5条回答
  • 2021-01-06 06:40

    To add to @Pino's answer, the reason why get() doesn't return an updated time is because setTimeZone() simply doesn't update the fields, just sets areAllFieldsSet to false, which is useless since get() doesn't check for it. If you ask me, this is very poorly coded from SUN's part. Here is the competent code from Calendar:

    setTimeZone():

        public void  setTimeZone(TimeZone value){
            zone = value;
            sharedZone = false;
            areAllFieldsSet = areFieldsSet = false;
    
        }
    

    get():

    protected final int internalGet(int field){
        return fields[field];
    }
    
    0 讨论(0)
  • 2021-01-06 06:43

    Are you restricted to using TimeZone and Calendar? If not I suggest using the excellent Library JodaTime which makes handling time zones much easier.

    Your example would then look like this:

    public static void convertTimeZoneJoda(String date, String time, DateTimeZone fromTimezone, DateTimeZone toTimeZone) {
        DateTimeFormatter dtf = DateTimeFormat.forPattern("dd/MM/yyyyHH:mm").withZone(fromTimezone);
        DateTime dt = dtf.parseDateTime(date+time).withZone(toTimeZone);
    
        System.out.println("Time in " + toTimeZone.getID() + " : " + dt.toString());
    }
    
    public static void main(String[] args) {
        convertTimeZoneJoda("23/04/2013", "23:00", DateTimeZone.forID("EST5EDT"), DateTimeZone.forID("GMT"));
    }
    

    JodaTime also allows for convenient conversation between TimeZone and DateTimeZone.

    0 讨论(0)
  • 2021-01-06 06:57

    This code works for me to convert to UTC:

    1. create a Calendar Object with UTC time zone

      Calendar utcTime = Calendar.getInstance(TimeZone.getTimeZone("GMT"));
      
    2. set the point in time in the UTC Calendar object from the "any time zone" Calendar object

      utcTime.setTimeInMillis(myCalendarObjectInSomeOtherTimeZone.getTimeInMillis());
      
    3. utcTime will now contain the same point in time as myCalendarObjectInSomeOtherTimeZone converted to UTC.

    0 讨论(0)
  • 2021-01-06 06:58

    The answer is partly explained in a commented section in setTimeZone():

    Consider the sequence of calls: cal.setTimeZone(EST); cal.set(HOUR, 1); cal.setTimeZone(PST). Is cal set to 1 o'clock EST or 1 o'clock PST? Answer: PST. More generally, a call to setTimeZone() affects calls to set() BEFORE AND AFTER it up to the next call to complete().

    In other words, the sequence

    1. Set Calendar time
    2. Change TimeZone

    is interpreted to mean "Use this time in this new time zone", while the sequence

    1. Set Calendar time
    2. Get the time (or some part of it)
    3. Change Time Zone

    will be interpreted as "Use this time in the old time zone, then change it".

    So, in your case, to get the behavior you are hoping for, you will need to call get(), or any other method that internally calls complete() inside the Calendar, before you change the time zone.

    0 讨论(0)
  • 2021-01-06 06:59

    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).

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

    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.

    See this example:

    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));
    }
    

    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.

    0 讨论(0)
提交回复
热议问题