0

I am displaying a date. The date varies with the Timezone of the device change. For example - Jan 01, 1960 for Timezone GMT +5.30 converts into Dec 31, 1959 for Timezone GMT -5.00. My requirement is that the date should be the same with any Timezone. I have converted my Date to UTC Date but still the date is changing according to Timezone. I have tried with few code as follows-

//Convering given date to UTC date using SimpleDateFormat
try {
        final DateFormat sdf = new SimpleDateFormat("EEE MMM dd HH:mm:ss Z yyyy");
        sdf.setTimeZone(TimeZone.getTimeZone("GMT"));
        final Date date = sdf.parse(givenDate + "");
        datePicker.setDate(date);
    } catch (ParseException exception) {
        exception.printStackTrace();
    }

or

// Converting given date into GMT date using Timezone defference
final TimeZone tzLocal = TimeZone.getDefault();
    final long gmtMillis = givenDate.getTime() - (tzLocal.getRawOffset());
    final Date date = new Date();
    date.setTime(gmtMillis);
datePicker.setDate(date);

I am using a custom DatePicker that has setDate(date) method (not android.widget.DatePicker).

I already have checked many similar Q&A but no luck. Thankyou

Ole V.V.
  • 81,772
  • 15
  • 137
  • 161
Kalu Khan Luhar
  • 1,044
  • 1
  • 22
  • 35
  • Consider throwing away the long outmoded and notoriously troublesome `SimpleDateFormat` and friends, and adding [ThreeTenABP](https://github.com/JakeWharton/ThreeTenABP) to your Android project in order to use `java.time`, the modern Java date and time API. It is so much nicer to work with. The modern `LocalDate` will probably solve your problem since it is a date without time zone. – Ole V.V. Jul 16 '19 at 14:25
  • Are we talking [`android.widget.DatePicker`](https://developer.android.com/reference/android/widget/DatePicker)? It seems from the documentation that that hasn’t got a `setDate` method. The way I read it, you need to use `updateDate`. – Ole V.V. Jul 16 '19 at 20:27
  • Thankyou Ole V.V, the I am using a custom DatePicker, so it has setDate(date) method. – Kalu Khan Luhar Jul 17 '19 at 06:17

1 Answers1

1

Not possible with java.util.Date

With java.util.Date you can’t. Despite the class name a Date does not represent a date. It is a point in time. So when the JVM’s default time zone may have changed since the Date was created, there is no way to detect which time zone was used when the Date was created. You can try all possible time zones, of course. This will typically give you two, occasionally three possible dates. Because it is never the same date in all time zones.

It may not be so bad as it sounds since the Date class is poorly designed and long outdated, so you shouldn’t use it anymore anyway.

Solution: java.time and ThreeTenABP

java.time, the modern Java date and time API, offers the LocalDate class. A LocalDate is a date without time of day and without time zone. So when you create a LocalDate worth Jan 01, 1960, it will always unambiguously be Jan 01, 1960.

    LocalDate date = LocalDate.of(1960, Month.JANUARY, 1);
    System.out.println(date);

There is nothing mysterious about the output:

1960-01-01

So the first suggestion is to base your custom DatePicker class on LocalDate rather than Date.

If you cannot afford to make that change right now, the short-term solution is to convert just before calling setDate (so only after the last change of default time zone has happened):

    Instant startOfDayInDefaultZone = date.atStartOfDay(ZoneId.systemDefault())
            .toInstant();
    Date oldFashionedDate = DateTimeUtils.toDate(startOfDayInDefaultZone);
    System.out.println(oldFashionedDate);

Output in my time zone was:

Fri Jan 01 00:00:00 CET 1960

Question: Can I use java.time on Android?

Yes, java.time works nicely on 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 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.

In the above code I am using the DateTimeUtils from the backport for converting from Instant to Date. If your Android version has java.time built in, instead use Date.from(startOfDayInDefaultZone) for this conversion.

Links

Ole V.V.
  • 81,772
  • 15
  • 137
  • 161