1

Could some one explain why this past date getting increased by one hour , when I convert it to Moscow Timezone ?

I'm using JDK 1.6.0_12 version.

.
2011-04-02T11:39:46+0300 --> Sat Apr 02 12:39:46 MSK 2011     // 11:39 --> 12:39

My current system time-zone is "Europe/Moscow" UTC+3 .

Also please note that this past date is in DST(Daylight Saving ) time-zone period UTC+4 , earlier used in Russia. There was a legislative change of Russian time-zone definitions in October 2014 . Since then Russia uses UTC+3 all through out a year .

I already checked this old post of 2014 .

But I think this issue looks different.

Our developers expect that every past date (like "2011-04-02T11:39:46+0300" and which is in DST period ), should contain current time zone offset value i.e +0300 , not +0400 . And they think JRE is converting it incorrectly to UTC+4 , though "Default Time Zone Offset" shows +3 here . Is this way of handling time-zone offset value for past dates correct?

Same output is given on JRE 1.8 , which I think is an updated version ,there shouldn't be any issue in TZ definition in JRE 1.8.

Thanks in Advance !

Java Code:

import java.text.SimpleDateFormat;
import java.util.TimeZone;
import java.util.Date;

public class HelloWorld{
    public static void main(String []args)
    {
        String dateInString = "2011-04-02T11:39:46+0300";
        System.out.println(dateInString);

        try {
            SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssZ");
            Date date = dateFormat.parse(dateInString);
            System.out.println(date);
        } catch (Exception e) {
            System.out.println(e);
        }

        final TimeZone tzone = TimeZone.getDefault();
        System.out.println("Default Time Zone ID - " + tzone.getID());
        System.out.println("Default Time Zone Offset - (" + (tzone.getRawOffset() / 60 / 60 / 1000) + ") hour.");
    }
}

Output :

2011-04-02T11:39:46+0300
Sat Apr 02 12:39:46 MSK 2011
Default Time Zone ID - Europe/Moscow
Default Time Zone Offset - (3) hour.
Ole V.V.
  • 81,772
  • 15
  • 137
  • 161
  • 1
    Even with the legislative changes; they only come into effect after the date they're applied, so the change to UTC+3 should not be retroactively applied to dates prior to 2014. – Anya Shenanigans Oct 13 '20 at 10:54
  • I recommend you don’t use `SimpleDateFormat`, `TimeZone` and `Date`. Those classes are poorly designed and long outdated, the first in particular notoriously troublesome. Instead use `OffsetDateTime`, `ZonedDateTime`, `ZoneId` and `DateTimeFormatter`, all from [java.time, the modern Java date and time API](https://docs.oracle.com/javase/tutorial/datetime/). – Ole V.V. Oct 14 '20 at 14:46
  • 1
    It’s a good, well considered question. You’ve explained what you found in a search and how it did not solve you issue, and you’ve provided a small and complete code example. Like very much. – Ole V.V. Oct 16 '20 at 09:28

3 Answers3

3

12:39 is the correct time

You are getting the correct result. In your string, 2011-04-02T11:39:46+0300, the trailing +0300 is an offset from UTC. So the point in time is the same as 2011-04-02T08:39:46+00:00 (UTC). As you say yourself, Moscow was at UTC offset +04:00 from 27 March 2011 to 26 October 2014. So to get the correct time for Moscow Java needs to add 1 hour to the hour in the string. Or 4 hours to the UTC hour of 08:39:46. In any case the time in Moscow was 12:39:46 at this point in time.

Or to answer your question:

… why this past date getting increased by one hour , when I convert it to Moscow Timezone ?

Because Moscow on that date was 1 hour ahead of the time in the string.

java.time

That said I agree with those who recommend java.time, the modern Java date and time API, for the job. SimpleDateFormat is a notorious troublemaker of a class, and Date and TimeZone are poorly and confusingly designed too. All are long outdated. The modern API is so much nicer to work with.

For example:

    ZoneId zone = ZoneId.of("Europe/Moscow");
    ZonedDateTime zdt = ZonedDateTime.of(2011, 4, 2, 11, 39, 46, 0, zone); 
    System.out.println(zdt);

Output:

2011-04-02T11:39:46+04:00[Europe/Moscow]

You can also see from the output that Java knows that Moscow was at offset +04:00 back then.

Your question very well illustrates why java.time (opposite the old TimeZone class) makes the distinction between a time zone and an offset. A time zone includes all historic, the present and all known future offsets from UTC. This is what you need to represent historic times in Moscow correctly. In java.time a time zone is identified by a ZoneId object and obeys a ZoneRules object (most often we need not concern ourselves with the latter and can just trust Java to make the right conversions). A UTC offset is represented by a ZoneOffset object.

Question: how could I use java.time with Java 1.6?

This is your lucky day. java.time exactly 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 either use desugaring or the Android edition of ThreeTen Backport. It’s called ThreeTenABP. In the latter case 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

Both modern java date/time api and legacy one (that is used in jdk1.6) rely on system unix time and the tzdata file bundled with the JRE. Looks like the developers are right and your java is using a very old one version of tzdata and your developers are right.

Also, the tzdata keeps information about legal changes and if you are trying to convert date/time in the past, it will apply conversion rules that were relevant at that time.

Regarding JDK 1.8: there was an update to Russian timezone information in 8u101, so you should use at least 8u101 for a better timezone conversion.

The best decision for you would be to use modern java or update your JREs tzdata manually if you really need to use an old one.

loginpassword
  • 307
  • 1
  • 5
  • 14
  • Thanks for responding . But I compiled and executed the program with latest the JRE 8u261 .and it contains the latest tzdata . You can check this site -->https://www.oracle.com/java/technologies/javase/8all-relnotes.html . The output of the above program is same . Still there is difference of 1 hours . That's why i asked whether taking current timezone offset (+0300 ) with the past date string instead of +0400 is correct or not . – user3148161 Oct 14 '20 at 08:04
0

You need to set time-zone to SimpleDateFormat as shown below:

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.TimeZone;

public class Main {
    public static void main(String[] args) throws ParseException {
        String dateInString = "2011-04-02T11:39:46+0300";
        SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssZ");
        dateFormat.setTimeZone(TimeZone.getTimeZone("Europe/Moscow"));// Set time-zone
        Date date = dateFormat.parse(dateInString);
        System.out.println(dateFormat.format(date));
    }
}

Output:

2011-04-02T12:39:46+0400

Note that java.util.Date does not have time-zone information. It's simply the number of milliseconds from the standard Java epoch of 1970-01-01T00:00:00Z where Z stands for UTC (0 hour offset), also known as Zulu time-zone. At any given moment, you will get the same number of milliseconds on the JVMs sitting in any part of the word. When you try to print an object of java.util.Date, the date-time string for the JVM's time-zone is calculated from this milliseconds value and the same is displayed. If you want to get the date-time String in a specific time-zone, you need to set it explicitly to the SimpleDateFormat and use the same to format the java.util.Date.

Arvind Kumar Avinash
  • 71,965
  • 6
  • 74
  • 110