Calendar.getInstance().getTime() returning date in “GMT” instead of Default TimeZone

元气小坏坏 提交于 2020-01-30 05:22:14

问题


Calendar c = Calendar.getInstance();
System.out.println(c.getTime());
c.set(2007, 0, 1);
System.out.println(c.getTime());

Output:

Tue Sep 12 12:36:24 IST 2017

Mon Jan 01 12:36:24 IST 2007

But, When I use the same code in a different environment, Output changes to below:

Output:

Tue Sep 12 12:36:24 IST 2017

Mon Jan 01 12:36:24 GMT 2007

FYI, I tried to print the timezone of the calendar instance, before and after setting the values and both are in "IST".

I want to know the root cause of this.


回答1:


The second output in your question is the correct and expected behaviour on a JVM running Irish time (Europe/Dublin). On September 12, 2017 Ireland is on summer time (DST). While it is not clearly documented, Date.toString() (which you invoke implicitly when printing the Date you get from c.getTime()) prints the date and time in the JVM’s time zone, which in September is rendered as IST for Irish Summer Time.

When you set the date on the Calendar object also using Irish time, the hour of day is preserved; in your case you get Jan 01 2007 12:36:24 Irish standard time. Now imagine the confusion if both Irish Summer Time and Irish Standard Time were rendered as IST. You would not be able to distinguish. Instead, since Irish standard time coincides with GMT, this is what Date.toString() prints when the date is not in the summer time part of the year (which January isn’t).

My guess is that your first output is from a JVM running India time. It too is rendered as IST, and since India doesn’t use summer time, the same abbreviation is given summer and winter.

java.time

Before understanding the explanation for the behaviour you observed, I posted a comment about the outdated and the modern Java date and time classes. I still don’t think the comment is way off, though. This is the modern equivalent of your code:

    ZonedDateTime zdt = ZonedDateTime.now(ZoneId.of("Europe/Dublin"));
    System.out.println(zdt);
    zdt = zdt.with(LocalDate.of(2007, Month.JANUARY, 1));
    System.out.println(zdt);

It prints

2017-09-12T11:45:33.921+01:00[Europe/Dublin]
2007-01-01T11:45:33.921Z[Europe/Dublin]

If you want to use the JVM’s time zone setting, use ZoneId.systemDefault() instead of ZoneId.of("Europe/Dublin"). As the name states, contrary to Date, ZonedDateTime does include a time zone. It corresponds more to the old Calendar class. As you can see, its toString method prints the offset from UTC (Z meaning zero offset) and the time zone name in the unambiguous region/city format. I believe that this leaves a lot less room for confusion. If you want to print the date in a specific format, use a DateTimeFormatter.

Appendix: sample output from your code

For the sake of completeness, here are the outputs from your code when running different time zones that may be rendered as IST:

  • Europe/Dublin (agrees with your second output)

    Tue Sep 12 11:19:28 IST 2017
    Mon Jan 01 11:19:28 GMT 2007
    
  • Asia/Tel_Aviv

    Tue Sep 12 13:19:28 IDT 2017
    Mon Jan 01 13:19:28 IST 2007
    
  • Asia/Kolkata (agrees with your first output)

    Tue Sep 12 15:49:28 IST 2017
    Mon Jan 01 15:49:28 IST 2007
    



回答2:


You need to set time zone and you will get desired result.

TimeZone.setDefault(TimeZone.getTimeZone("IST"));

Here is a working code.

import java.util.Calendar;
import java.util.TimeZone;  
public class Cal {

    public static void main(String[] args) {
        // TODO Auto-generated method stub
        TimeZone.setDefault(TimeZone.getTimeZone("IST")); // Add this before print
        Calendar c = Calendar.getInstance();    
        System.out.println(c.getTime());
        c.set(2007, 0, 1);
        System.out.println(c.getTime());
    }

}

As per Doc "Typically, you get a TimeZone using getDefault which creates a TimeZone based on the time zone where the program is running. For example, for a program running in Japan, getDefault creates a TimeZone object based on Japanese Standard Time."

SO when you running in different timezone it is using as default timezone. Hope you clear now. I attach doc. please read.




回答3:


To talk about this interesting behaviour:

The source code from the Calendar class:

public final void set(int year, int month, int date)
{
    set(YEAR, year);
    set(MONTH, month);
    set(DATE, date);
}

Which leads to the set method:

public void set(int field, int value)
{
    // If the fields are partially normalized, calculate all the
    // fields before changing any fields.
    if (areFieldsSet && !areAllFieldsSet) {
        computeFields();
    }
    internalSet(field, value);
    isTimeSet = false;
    areFieldsSet = false;
    isSet[field] = true;
    stamp[field] = nextStamp++;
    if (nextStamp == Integer.MAX_VALUE) {
        adjustStamp();
    }
}

The interesting part here is the computeFields() method which has two implementation (one for Gregorian and one for Japenese calendar). These methods are quite complex but as far as I can see this is the only place where your Calendar instance may change time zone in your usecase.



来源:https://stackoverflow.com/questions/46170216/calendar-getinstance-gettime-returning-date-in-gmt-instead-of-default-time

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!