Harsh4789
Harsh4789

Reputation: 697

Calender class gives different dates on different device

I'm using following code. Values (hour, minute, second, date, month, year, day_of_week) are hardcoded for simplicity.

Calendar c = Calendar.getInstance();
c.set(Calendar.HOUR_OF_DAY, 10);
c.set(Calendar.MINUTE, 0);
c.set(Calendar.SECOND, 0);
c.set(Calendar.DATE, 2);
c.set(Calendar.MONTH, Calendar.APRIL);
c.set(Calendar.YEAR, 2018);
c.setFirstDayOfWeek(Calendar.MONDAY);
c.set(Calendar.DAY_OF_WEEK, Calendar.MONDAY);

String date = String.format(Locale.US, "%1$tA %1$tb %1$td %1$tY at %1$tI:%1$tM %1$Tp", c);
Log.e("date", date);

Observation 1

This code prints the the following on the Titanium S1 (Android 4.1.2)

E/date: Monday Mar 26 2018 at 10:00 AM

This code prints the the following on the Moto G4+ (Android 7.0), Moto G5+ (Android 7.0)

E/date: Monday Apr 02 2018 at 10:00 AM

Observation 2 This difference appears only on 2nd April & 2nd July to my knowledge. I am seeing the first day of month is Sunday for both the April and July month. It works fine for rest of the days

Question 1) Does the first day of month (MONDAY) cause this difference? Changing it to SUNDAY seems working on these two days. But I am not sure this works in all the scenarios.

This is affecting users on my app. Please help. Thanks.

Upvotes: 0

Views: 161

Answers (1)

uilon
uilon

Reputation: 135

I've made some test in JDK 7 and the results don't seem to be affected by setFirstDayOfWeek. Actually, it seems to be related to the JVM default locale (java.util.Locale).

When the default locale is Japanese or Thai, the final result is March. Somehow, the JVM default locale affects the internals of Calendar, in some misterious ways that, I must admit, are beyond my understanding. But anyway, one way to fix it is to set in the Calendar the same locale you used in the output:

Calendar c = Calendar.getInstance(Locale.US);

This fixed the issue for me.

java.time API

This bizarre behaviour is one of the reasons to not use the old Calendar API (there are many others, btw).

In Android, it's possible to use the java.time API. In API level 26, the java.time classes are available. For lower levels, you can use this backport - and in this link there are instuctions to configure it in Android.

With this new API, it's much easier - and less error prone - to get what you want. To build a specific date/time, use a ZonedDateTime class, and a DateTimeFormatter to convert it to a String in a specific format:

// April 2nd 2018, 10 AM
ZonedDateTime dt = ZonedDateTime.of(2018, 4, 2, 10, 0, 0, 0, ZoneId.systemDefault());
DateTimeFormatter fmt = DateTimeFormatter.ofPattern("EEEE MMM dd yyyy 'at' hh:mm a", Locale.US);
String formattedDate = dt.format(fmt); // Monday Apr 02 2018 at 10:00 AM

Note that the day of week is adjusted automatically, based on the day/month/year values provided.

To get the current date/time, just use ZonedDateTime.now(ZoneId.systemDefault()) (to get the current date/time in JVM's default timezone), or use ZoneId.of("zone name") to use a specific timezone - replace "zone name" with any valid IANA zone's names.

Upvotes: 2

Related Questions