Java Calendar adds a random number of milliseconds?

后端 未结 4 888
栀梦
栀梦 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条回答
  •  日久生厌
    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.

提交回复
热议问题