Search code examples
javaandroidtimezonedayofweekandroid-date

java TimeZone and TimeUnit and SimpleDateFormat in Android


https://gist.github.com/anonymous/e14bbbb89dd8636f1237c73dc8878b3f

I've encountered a bug in this code that causes the last switch statement (line 298 - 307) to return the default for the current day and case 0 for the next day when my emulators time zone is set to the other side of the GMT+0 line than the data set is coming from. (I.e. the system time in Asia, like Beijing, and the data set from eastern time zone, like Atlanta)

How can I update it to account for systems in other timezones checking data provided from a zone on the other side of the GMT+0 line?


Solution

  • If you trust that your JVM’s time zone setting reflects the user’s time zone, here is the modern and correct way to get the number of days from today to the provided day in that time zone:

    private static String getDayName(Context context, long dateInMillis) {
        ZoneId zone = ZoneId.systemDefault();
        LocalDate providedDate = Instant.ofEpochMilli(dateInMillis)
                .atZone(zone)
                .toLocalDate();
        LocalDate today = LocalDate.now(zone);
    
        int daysAfterToday = (int) ChronoUnit.DAYS.between(today, providedDate);
    
        switch (daysAfterToday) {
            case 0:
                return context.getString(R.string.today);
            case 1:
                return context.getString(R.string.tomorrow );
    
            default:
                return providedDate.getDayOfWeek()
                            .getDisplayName(TextStyle.FULL, 
                                            Locale.getDefault(Locale.Category.FORMAT));
        }
    }
    

    I say “If you trust that your JVM’s time zone setting reflects the user’s time zone” because the time zone setting may be changed by other parts of your program or other programs running in the same JVM. If you know the user’s time zone better, you should of course use your knowledge, for example:

        ZoneId zone = ZoneId.of("America/Cordoba");
    

    I’d prefer to insert a check that daysAfterToday is the interval 0 through 6. Before converting from long to int.

    I am using and warmly recommending java.time, the modern Java date and time API. It is so much nicer to work with than the outdated TimeZone class and the notoriously troublesome SimpleDateFormat that you were using.

    Question: Can I use java.time with my API level?

    Yes, java.time works nicely on older and newer Android devices.

    • In Java 8 and later and on new Android devices (from API level 26, I’m told) the new API comes built-in.
    • In Java 6 and 7 get the ThreeTen Backport, the backport of the new classes (ThreeTen for JSR 310, where the modern API was first described).
    • On (older) Android, use the Android edition of ThreeTen Backport. It’s called ThreeTenABP. Make sure you import the date and time classes from package org.threeten.bp and subpackages.

    Links