Java Calendar adds a random number of milliseconds?

后端 未结 4 841
栀梦
栀梦 2021-01-21 14:59

Hi I have something weird happening. I am simply taking a calendar object, converting it to its individual parts, and putting it back into a calendar (with or without any change

相关标签:
4条回答
  • As per my comments under your question , there is only difference in seconds and milliseconds between startCalendar and calendarStart time, because that values were not reset.

    See DEMO

    0 讨论(0)
  • 2021-01-21 15:50

    When you initialize the Calendar object, it is getting the current time including the current second and millisecond. The code provided sets the hour and minute, but it does not set the second and millisecond, leaving it as it was when the Calendar object was initialized. In order to set the second and nanosecond to zero, use:

    StartCalendar.set(Year, Month, DayofMonth, Hour, Minute, 0,0);
    
    0 讨论(0)
  • 2021-01-21 15:51

    In the documentation of Calendar.set, it is said :

    Sets the values for the fields YEAR, MONTH, DAY_OF_MONTH, HOUR, MINUTE, and SECOND. Previous values of other fields are retained. If this is not desired, call clear() first.

    The reason is that not all fields are set with this method, in you case, you don't have MILLISECOND set. So it keep the value when the instance was created.

    The call of Calendar.clear will

    Sets all the calendar field values and the time value (millisecond offset from the Epoch) of this Calendar undefined.

    A quick example :

        Calendar c = GregorianCalendar.getInstance();
        c.clear();
        c.set(2019, Calendar.NOVEMBER, 03, 16, 15, 03);
    
        System.out.println(c.getTime());
        System.out.println(c.getTimeInMillis());
    

    Sun Nov 03 16:15:03 CET 2019
    1572794103000

    Milliseconds being undefined will give 0

    0 讨论(0)
  • 2021-01-21 15:55

    java.time and ThreeTenABP

    I suggest that you use java.time, the modern Java date and time API, for your date and time work. For example:

        ZonedDateTime start = ZonedDateTime.now(ZoneId.systemDefault());
        ZonedDateTime end = start;
        
        System.out.println("Start: " + start);
        System.out.println("End:   " + end);
    

    Output when I ran the code in my time zone just now:

    Start: 2020-06-24T19:24:04.811+02:00[Europe/Copenhagen]
    End:   2020-06-24T19:24:04.811+02:00[Europe/Copenhagen]
    

    A ZonedDateTime is a date and time of day in some time zone. It’s the closest we come to a modern equivalent of GregorianCalendar (the subclass of Calendar that your code gave you). Which modern class to use varies with more precise requirements, so sometimes you will prefer to use for example LocalDate, OffsetDateTime or even LocalTime.

    To truncate the values to whole minutes (setting seconds and fraction of second to 0):

        ZonedDateTime start = ZonedDateTime.now(ZoneId.systemDefault())
                .truncatedTo(ChronoUnit.MINUTES);
    
    Start: 2020-06-24T19:24+02:00[Europe/Copenhagen]
    

    ZonedDateTime and the other classes of java.time offer plenty of ways to modify the values obtained. For example:

        ZonedDateTime end = start.plusDays(2).withHour(13);
    
    End:   2020-06-26T13:24+02:00[Europe/Copenhagen]
    

    If you want to create the end time manually using only selected fields from the start time:

        ZonedDateTime end = ZonedDateTime.of(
                2021, start.getMonthValue(), start.getDayOfMonth(),
                start.getHour(), 30, 0, 0, start.getZone());
    
    End:   2021-06-24T19:30+02:00[Europe/Copenhagen]
    

    What went wrong in your code?

    Part of the answer is already in the other answers: The set methods of Calendar set only the fields they promise to set and leave other fields unchanged where possible. While this is probably expected from the set​(int field, int value) method, it often surprises with the set​(int year, int month, int date) method and even more with set​(int year, int month, int date, int hourOfDay, int minute) and set​(int year, int month, int date, int hourOfDay, int minute, int second). In general while well intended the Calendar class and its subclasses are poorly and confusingly designed and cumbersome to work with. This is the main reason why I recommend java.time above.

    The other part of the answer is that Calendar calculates its fields leniently. So when you look at the Calendar object in your debugger after calling set, it will contain a lot of garbage values. Calling getTime() forces the Calendar to compute its fields, so after that call the way it looks in the debugger should make more sense. Again it’s confusing behaviour, and it can also sometimes be observed without using the debugger.

    Question: Doesn’t java.time require Android API level 26?

    java.time works nicely on both older and newer Android devices. It just requires at least Java 6.

    • In Java 8 and later and on newer Android devices (from API level 26) the modern API comes built-in.
    • In non-Android Java 6 and 7 get the ThreeTen Backport, the backport of the modern classes (ThreeTen for JSR 310; see the links at the bottom).
    • On (older) Android use the Android edition of ThreeTen Backport. It’s called ThreeTenABP. And make sure you import the date and time classes from org.threeten.bp with subpackages.

    Links

    • Oracle tutorial: Date Time explaining how to use java.time.
    • Java Specification Request (JSR) 310, where java.time was first described.
    • ThreeTen Backport project, the backport of java.time to Java 6 and 7 (ThreeTen for JSR-310).
    • ThreeTenABP, Android edition of ThreeTen Backport
    • Question: How to use ThreeTenABP in Android Project, with a very thorough explanation.
    0 讨论(0)
提交回复
热议问题