glend
glend

Reputation: 1622

Handling date/time in java/android and daylight savings

I am making a diary application for Android and I want to allow the user to select the timezone they are in. Time has always been a area of confusion for me programatically.

I am going to create an enum for the available timezones.

I am going to save date/time entries to a sqlite in long UTC format, then handling offsets and DST programmatically in Java for display purposes.

I am actually aware of Java's limitations when it comes to date/time handling.

Calendar utc = Calendar.getInstance(TimeZone.getTimeZone("UTC")); //returns the current time in UTC format
Long utcLong = utc.getTimeInMillis(); //returns current utc time in long for database insertion

Question 1: How would I apply an offset to it and account for when to apply any additional DST offsets? Because not all timezones observe DST and DST comes into effect at different dates for different timezones.

Question 2: Java's TimeZone class has something like ~800 ids, it would be annoying to the user to have to scroll through ~800 options to find the one that applys to them. Is there a short list available? I'm thinking there are around ~50 useful timezones.

Upvotes: 5

Views: 3620

Answers (1)

user7605325
user7605325

Reputation:

First of all, I recommend you to not use the Calendar class. It's outdated and has lots of bugs and design issues. This terrible API was replaced by much better ones:

The code below works for all, the only difference is the package names (in Java 8 is java.time and in ThreeTen Backport is org.threeten.bp), but the classes and methods names are the same.

To get the UTC current date/time, the best choice is to use Instant class:

// current date/time in UTC - now() always returns the current instant in UTC
Instant instant = Instant.now();
System.out.println(instant); // 2017-06-03T18:03:55.976Z

// equivalent to calendar.getTimeInMillis(), it returns a long
System.out.println(instant.toEpochMilli()); // 1496513035976

To convert this instant to a timezone, you can use the ZoneId with a ZonedDateTime:

// ZoneId accepts the same IDs used by TimeZone
ZoneId zone = ZoneId.of("America/Sao_Paulo");
// convert instant to timezone
ZonedDateTime z = instant.atZone(zone);
System.out.println(z); // 2017-06-03T15:03:55.976-03:00[America/Sao_Paulo]

// converts back to UTC (returns an Instant)
System.out.println(z.toInstant()); // 2017-06-03T18:03:55.976Z

The code above already takes care of DST changes, so the conversion from and to UTC is straightforward.

Timezone list

You say that you have a list of ~50 "useful" timezones. I don't know what criteria you used to define that list, but what happens if an user is in a timezone that's not in the list?

There are some ideas of timezone-picking user interfaces in this link and here. You can choose one and adapt to your app.

I also suggest to not use (if possible) the 3-letter timezone abbreviations (like CST or PST) because they are ambiguous and not standard. It's better to use the full names (like America/Sao_Paulo or Europe/London) as they are the ones used by Java's APIs (you can get the full list with ZoneId.getAvailableZoneIds()) and they are configured with all DST changes for each zone.

Upvotes: 7

Related Questions