0

My Android app (in java, within Android Studio) uses class `Calendar'. After

Calendar cal=Calendar.getInstance();
cal.setTimeInMillis(0);
Log.i("Interim",cal.getTime().toString());

such output is producing: I/Interim: Thu Jan 01 03:00:00 GMT+02:00 1970. My timezone is GMT+02:00 (Kyiv, Ukraine), DST at January is not applied. Why is Calendar time set to 03:00? I expect 00:00 (not taking into account timezone) or 02:00 (taking timezone), but why 03:00?

Thanks in advance for any idea

PS To clarify circumstance, I set Calendar timezone to GMT and get hour value:

Calendar cal=Calendar.getInstance(TimeZone.getTimeZone("GMT"));
cal.setTimeInMillis(0);
Log.i("Interim hours",Integer.toString(cal[i].get(Calendar.HOUR)));
Log.i("Interim",cal.getTime().toString());

On contrary to expected, output is:

I/Interim hours: 0

I/Interim: Thu Jan 01 03:00:00 GMT+02:00 1970

So, value of hour field is 0, but time is 03:00. I've just heard about 1 hour shift at 13/06/1975 (see the answer below), but this seems to concern Vietnam TZ only, doesn't it?

Community
  • 1
  • 1
Spectorsky
  • 608
  • 4
  • 23
  • The most likely reason is that the time zone rules in 1970 weren't the same as they are now. One of the reasons timezones are even more complicated that most developers realize is that the rules change all the time and all sane time libraries need to take that into consideration. For example from 1943 to 1990 Europe/Kiev apparently used 1:00 as the standard offset. – Joachim Sauer Mar 20 '20 at 12:20
  • 1
    I recommend you don’t use `Calendar`. That class is poorly designed and long outdated. Instead use `ZonedDateTime` or another class from [java.time, the modern Java date and time API](https://docs.oracle.com/javase/tutorial/datetime/). If for Andoird API level under 26, then through [ThreeTenABP](https://github.com/JakeWharton/ThreeTenABP), – Ole V.V. Mar 20 '20 at 16:06

2 Answers2

2

Please make the distinction between a time zone and an offset. Your time zone is Europe/Kiev (English spelling of place names in time zone IDs is used where an English spelling exists). Europe/Kiev is at offset +02:00 here in January. It was at offset +03:00 until 27 October and will be again from 29 March because of summer time (daylight saving time, DST). And what may surprise some, it was on offset +03:00 permanently from 1944 through 1980. So at the epoch — Jan 1 1970 00:00 UTC — the time in Ukraine was 3:00. So for Ukraine this part of your output is correct.

In short: a time zone encompasses the historic, present and known future offsets from UTC/GMT used in that time zone. GMT+02:00 is an offset, it is not a time zone.

java.time and ThreeTenABP

Here is the modern way of obtaining what I think you were after:

    ZonedDateTime epochInUkraine = Instant.EPOCH.atZone(ZoneId.of("Europe/Kiev"));
    System.out.println(epochInUkraine);

Output from these lines is:

1970-01-01T03:00+03:00[Europe/Kiev]

If you want a printout similar to the one you got from printing an old-fashioned java.util.Date object:

    DateTimeFormatter formatter = DateTimeFormatter.ofPattern(
            "EEE MMM dd HH:mm:ss zzz yyyy", Locale.ROOT);
    System.out.println(epochInUkraine.format(formatter));

Thu Jan 01 03:00:00 EET 1970

You can probably find an output format that suits your audience still better, though. I am leaving that part to yourself.

What went wrong?

Why does Calendar.setTimeInMillis(0) set incorrect time?

It does not. The Calendar class and its subclasses are poorly designed and long outdated, but setTimeInMillis(0) sets the correct time. You also already noticed that when your Calendar is in UTC, its clock hour of the morning or afternoon (0 thorugh 11) is 0. How you got the output of 03:00:00 GMT+02:00 with the contradiction between 03:00 and +02:00? Possible explanations include:

  • Most likely an error on your side. Either this didn’t come from the Calendar that you had set to 0, or your copied the output inaccurately when typing your question. If you check once more whether you can reproduce that output, I’d be curious to hear.
  • Less likely a bug in Date.toString(), which gets called implicitly when you print the Date that you get from cal.getTime().
  • Still less likely a bug in Calendar.getTime() that gives you the wrong Date object from the Calendar.

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.

Links

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

If your input is before 13/06/1975, result always +1 hours. That day has 25 hours. You can check on it https://currentmillis.com/ . If input 13/06/1975 we got 171824400000 and 12/06/1975 we got 171734400000.

171824400000 - 171734400000 = 90000000.

90000000 / (60*60*1000) = 25 (???)

So I'd think you can plus 1 hours if your input before 13/06/1975