2
public static void main(String[] args) {
    String opDate = "Tue Jan 03 00:00:00 MSK 2006";
    String date = convertDate(opDate, "yyyyMMdd");
            
    System.out.println("opDate: " + opDate);
    System.out.println("date: " + date);
}

public static String convertDate(String opDate, String dateFormat) {
    Date date = new Date();
                                                    //  Mon Jan 02 00:00:00 MSK 2006
    SimpleDateFormat dateParser = new SimpleDateFormat("EEE MMM dd HH:mm:ss zzz yyyy", Locale.US);
    
    try {
        date = dateParser.parse(opDate);
    } catch (Exception e) {
        System.out.println("exception = " + e.toString());
    }
    
    SimpleDateFormat df = new SimpleDateFormat(dateFormat);
    df.setTimeZone(TimeZone.getTimeZone("Russia/Moscow"));
    String strDate = df.format( date.getTime() );
    
    return strDate.trim();
}

out:

opDate: Tue Jan 03 00:00:00 MSK 2006

date: 20060102

Why does it return Jan 02?

Community
  • 1
  • 1
VextoR
  • 5,087
  • 22
  • 74
  • 109
  • Did you check the time and timezone? I assume the date is returned as GMT and thus might be Jan 2nd 21:00:00. – Thomas Mar 27 '12 at 11:12
  • Might have something to do with the timestamp. Try by defining the opDate string like this: String opDate = "Tue Jan 03 01:00:00 MSK 2006"; and see if it helps – John Snow Mar 27 '12 at 11:12
  • Probably something to do with time zones. – ftr Mar 27 '12 at 11:12

6 Answers6

8

The problem is the fetching of the "Russia/Moscow" time zone. The correct zoneinfo ID is "Europe/Moscow". Change the ID, and the problem goes away:

df.setTimeZone(TimeZone.getTimeZone("Europe/Moscow"));

It's unfortunate that TimeZone.getTimeZone("random rubbish") returns the UTC time zone rather than letting you know in some way that it's broken.

Jon Skeet
  • 1,421,763
  • 867
  • 9,128
  • 9,194
5

Probably due to timezone conversion. I would suggest you also print the time and the timezone of your resulting date. This is likely to be Jan 2, 23:00 or something.

This happens because you set a different timezone on the SimpleDataFormat.

Steven De Groote
  • 2,187
  • 5
  • 32
  • 52
3

Timezones.

You're specifying midnight on January 3rd in MSK. This is 9pm on the 2nd January in GMT (the likely default timezone).

I can see that you're trying to output in Moscow time as well, but Russia/Moscow is not a valid timezone, and the getTimeZone call "helpfully" silently defaults to returning GMT. This then of course doesn't change the time zone of the date when formatting and outputs it as 2 Jan.

If you set the timezone to Europe/Moscow, you'll get the expected output.

Andrzej Doyle
  • 102,507
  • 33
  • 189
  • 228
2

May it be related to the fact that you're converting dates between two distinct TimeZones?

pcalcao
  • 15,789
  • 1
  • 44
  • 64
1

java.time

The java.util Date-Time API and their formatting API, SimpleDateFormat are outdated and error-prone. It is recommended to stop using them completely and switch to the modern Date-Time API*.

Solution using java.time, the modern Date-Time API:

import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Locale;

public class Main {
    public static void main(String[] args) {
        String strDateTime = "Tue Jan 03 00:00:00 MSK 2006";
        String formatted = formatDateTimeStringTo(strDateTime, "yyyyMMdd", Locale.ENGLISH);

        System.out.println("opDate: " + strDateTime);
        System.out.println("date: " + formatted);
    }

    public static String formatDateTimeStringTo(String strDateTime, String targetFormat, Locale locale) {
        DateTimeFormatter parser = DateTimeFormatter.ofPattern("EEE MMM d H:m:s zzz u", locale);
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern(targetFormat, locale);
        ZonedDateTime zdt = ZonedDateTime.parse(strDateTime, parser);
        // System.out.println(zdt); // 2006-01-03T00:00+03:00[Europe/Moscow]
        return zdt.format(formatter);
    }
}

Output:

opDate: Tue Jan 03 00:00:00 MSK 2006
date: 20060103

ONLINE DEMO

Learn more about the modern Date-Time API from Trail: Date Time.

Follow the standard convention to name the timezone:

Ask your publisher to switch to the standard naming convention of the timezone. The standard naming convention is Region/City e.g. Europe/Moscow. The two/three/four letter abbreviation for the timezone is error-prone as described in the following text at the Timezone documentation page:

Three-letter time zone IDs

For compatibility with JDK 1.1.x, some other three-letter time zone IDs (such as "PST", "CTT", "AST") are also supported. However, their use is deprecated because the same abbreviation is often used for multiple time zones (for example, "CST" could be U.S. "Central Standard Time" and "China Standard Time"), and the Java platform can then only recognize one of them.


* For any reason, if you have to stick to Java 6 or Java 7, you can use ThreeTen-Backport which backports most of the java.time functionality to Java 6 & 7. If you are working for an Android project and your Android API level is still not compliant with Java-8, check Java 8+ APIs available through desugaring and How to use ThreeTenABP in Android Project.

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

If you change line:

String date = convertDate(opDate, "yyyyMMdd");

to:

String date = convertDate(opDate, "EEE MMM dd HH:mm:ss zzz yyyy");

you can see the output of your program:

opDate: Tue Jan 03 00:00:00 MSK 2006
date: Mon Jan 02 20:00:00 GMT 2006

You are not setting well TimeZone with:

df.setTimeZone(TimeZone.getTimeZone("Russia/Moscow"));

you need:

df.setTimeZone(TimeZone.getTimeZone("Europe/Moscow"));

Finally there are summer delay of 1h.

logoff
  • 3,347
  • 5
  • 41
  • 58