Search code examples
javaandroiddatetimedate-conversion

How to get start time and end time of a day in another timezone in Android


I've the date in format: YYYY-MM-DD

Output format required is: "yyyy-MM-dd'T'HH:mm:ss.SSS'Z'"

And I want to get the date in ISO format as Start time of the day(starts from 12:00AM) and end time of the day(ends on 11:59PM) in America/Chicago timezone.

For eg. For the date: 2020-06-08 (June 8) the converted final output is like:

Start time of the day as Date: 2020-06-08T05:00:00.000Z

End time of the day as Date: 2020-06-09T04:59:59.999Z

Please help me here if anybody has any clue for the same.


Solution

  • java.time and ThreeTenABP

    I suggest using java.time, the modern Java date and time API, for such date and time math.

        ZoneId zone = ZoneId.of("America/Chicago");
    
        String dateString = "2020-06-08";
        LocalDate date = LocalDate.parse(dateString);
        Instant startOfDay = date.atStartOfDay(zone).toInstant();
        Instant endOfDay = date.plusDays(1).atStartOfDay(zone).toInstant();
    
        System.out.println("The day is from " + startOfDay + " (inclusive) to " + endOfDay + " (exclusive)");
    

    Output is:

    The day is from 2020-06-08T05:00:00Z (inclusive) to 2020-06-09T05:00:00Z (exclusive)

    In order not to exclude the last millisecond of the day we need to count the day as lasting up to the first moment of the next day exclusive. If you do insist on subtracting a millisecond or just a nanosecond, it’s up to you to do so, of course. For example:

        Instant endOfDay = date.plusDays(1).atStartOfDay(zone).minusNanos(1).toInstant();
    

    The day is from 2020-06-08T05:00:00Z (inclusive) to 2020-06-09T04:59:59.999999999Z (inclusive and 1 nano more)

    Edit: How to get milliseconds printed in the output? You most probably don’t need that. The format you are asking for is ISO 8601 (see the link at the bottom), the international standard. In ISO 8601 the fraction of second is optional, and leaving it out implies 0. So any API requiring ISO 8601 should accept the above. Only if not, the correct solution is to use a formatter. In this case we need to convert the time to UTC explicitly:

        ZoneId zone = ZoneId.of("America/Chicago");
        DateTimeFormatter formatterWithMillis = DateTimeFormatter.ofPattern("uuuu-MM-dd'T'HH:mm:ss.SSSX");
    
        String dateString = "2020-06-08";
        LocalDate date = LocalDate.parse(dateString);
        OffsetDateTime startOfDay = date.atStartOfDay(zone)
                .toOffsetDateTime()
                .withOffsetSameInstant(ZoneOffset.UTC);
        OffsetDateTime endOfDay = date.plusDays(1)
                .atStartOfDay(zone)
                .toOffsetDateTime()
                .withOffsetSameInstant(ZoneOffset.UTC);
    
        String startString = startOfDay.format(formatterWithMillis);
        String endString = endOfDay.format(formatterWithMillis);
        System.out.println("The day is from " + startString + " (inclusive) to " + endString + " (exclusive)");
    

    The day is from 2020-06-08T05:00:00.000Z (inclusive) to 2020-06-09T05:00:00.000Z (exclusive)

    Or after subtracting a nanosecond from the end time as before:

        OffsetDateTime endOfDay = date.plusDays(1)
                .atStartOfDay(zone)
                .minusNanos(1)
                .toOffsetDateTime()
                .withOffsetSameInstant(ZoneOffset.UTC);
    

    The day is from 2020-06-08T05:00:00.000Z (inclusive) to 2020-06-09T04:59:59.999Z (inclusive and 1 nano more)

    (Since the time is truncated to whole milliseconds the 1 nano more doesn’t really make sense, but I don’t think that’s the point here.)

    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.

    But don't we have any other option apart from switching to ThreeTenBP Library?

    If you insisted, I suppose that a way through using Calendar, Date and SimpleDateFormat could be found. Those classes are poorly designed and long outdated, so with what I know and don’t know I would prefer ThreeTenABP.

    Links