Setting values of Java Calendar does not give expected date-time

后端 未结 5 1091
谎友^
谎友^ 2021-01-02 02:25

I have an hour, minute, date and millisecond timestamp, and am trying to create a Date object representing the time. The timestamp is provided in Eastern Daylight Time.

相关标签:
5条回答
  • 2021-01-02 02:27

    From the Calendar Documentation

    Under the Field Manipulation section:

    set(f, value) changes calendar field f to value. In addition, it sets an internal member variable to indicate that calendar field f has been changed. Although calendar field f is changed immediately, the calendar's time value in milliseconds is not recomputed until the next call to get(), getTime(), getTimeInMillis(), add(), or roll() is made.

    Thus, multiple calls to set() do not trigger multiple, unnecessary computations. As a result of changing a calendar field using set(), other calendar fields may also change, depending on the calendar field, the calendar field value, and the calendar system. In addition, get(f) will not necessarily return value set by the call to the set method after the calendar fields have been recomputed. The specifics are determined by the concrete calendar class.

    0 讨论(0)
  • 2021-01-02 02:29

    As mentioned by gtgaxiola: From the Calendar Documentation

    Under the Field Manipulation section:

    set(f, value) changes calendar field f to value. In addition, it sets an internal member variable to indicate that calendar field f has been changed. Although calendar field f is changed immediately, the calendar's time value in milliseconds is not recomputed until the next call to get(), getTime(), getTimeInMillis(), add(), or roll() is made.

    The problem is that your getTime() call recomputes the date but setTimeZone(..) doesn't set the internal member variable isTimeSet to false. So the last line in your first output is wrong for you because you expect the timezone to be considered which is not.

    0 讨论(0)
  • 2021-01-02 02:46

    You need to set the time zone first. See the definition of GregorianCalendar.setTimeZone below:

    public void setTimeZone(TimeZone value)
    {
        zone = value;
        sharedZone = false;
        /* Recompute the fields from the time using the new zone.  This also
         * works if isTimeSet is false (after a call to set()).  In that case
         * the time will be computed from the fields using the new zone, then
         * the fields will get recomputed from that.  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().
         */
        areAllFieldsSet = areFieldsSet = false;
    }
    
    0 讨论(0)
  • 2021-01-02 02:48

    I would simply set the time zone first:

     Calendar cal = GregorianCalendar.getInstance();
    
        cal.clear();
        cal.setTimeZone(TimeZone.getTimeZone("EDT"));
        cal.setTime(today);
        cal.set(Calendar.HOUR_OF_DAY,hour);
        cal.set(Calendar.MINUTE,min);
        cal.set(Calendar.SECOND,sec);
        cal.set(Calendar.MILLISECOND,ms);
    

    However it was doing what it should, as said in the comments 4am is 11pm in EST.

    And even better solution would be not to use Calendar at all but joda-time for instance.

    EDIT: This produces the right time for me.

        Date today = new Date();
        int hour = 4, min  = 0, sec  = 0, ms   = 64;
        boolean print = false;
    
        Calendar cal = GregorianCalendar.getInstance();
        if(print)
            System.out.println("After initializing, time is: "+cal.getTime());
        cal.clear();
        if(print)
            System.out.println("After clearing, time is: "+cal.getTime());
        cal.setTimeZone(TimeZone.getTimeZone("EDT"));
        if(print)
            System.out.println("After setting time zone, time is: "+cal.getTime());
        cal.setTime(today);
        if(print)
            System.out.println("After setting date, time is: "+cal.getTime());
        cal.set(Calendar.HOUR_OF_DAY,hour);
        if(print)
            System.out.println("After setting hour, time is: "+cal.getTime());
        cal.set(Calendar.MINUTE,min);
        if(print)
            System.out.println("After setting minute, time is: "+cal.getTime());
        cal.set(Calendar.SECOND,sec);
        if(print)
            System.out.println("After setting second, time is: "+cal.getTime());
        cal.set(Calendar.MILLISECOND,ms);
        if(print)
            System.out.println("After setting milliseconds, time is: "+cal.getTime());
    
        System.out.println("TIME: "+cal.getTime());
    
    0 讨论(0)
  • 2021-01-02 02:51

    You create an instance of the current date in GMT:

    Calendar cal = GregorianCalendar.getInstance();
    cal.setTime(today);
    

    Then you change the time to 4 AM:

    cal.set(Calendar.HOUR_OF_DAY,hour);
    cal.set(Calendar.MINUTE,min);
    cal.set(Calendar.SECOND,sec);
    

    Afterwards, you convert the date from GMT to EST which is 23 00:

    cal.setTimeZone(TimeZone.getTimeZone("EDT"));
    

    A debugger will help you see these changes each step of the way :)

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