Search code examples
javaandroidsimpledateformat

SimpleDateFormat shows wrong local Time


I want to store a string into a databse (SQLite) for an Android App with the current time and date. For that purpose I am using SimpleDateFormat. Unfortunately it does not show the correct time when. I tried two options.

First Option (from SimpleDateFormat with TimeZone)

SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss Z", Locale.getDefault());
        sdf.format(new Date());

Second option (from Java SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'") gives timezone as IST)

    SimpleDateFormat sdf2 = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss'Z'");
    sdf2.setTimeZone(TimeZone.getTimeZone("CEST"));

In both cases the time is just wrong. It is not the local time that my laptop or phone is showing but the output time is 2 hours earlier. How can I change that? I would like to have the current time of Berlin (CEST) that is also shown on my computer. I appreciate every comment.


Solution

  • Use Europe/Berlin instead of CEST and you will get the expected result.

    import java.text.SimpleDateFormat;
    import java.util.Date;
    import java.util.TimeZone;
    
    public class Main {
        public static void main(String[] args) {
            SimpleDateFormat sdf2 = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss Z");
            sdf2.setTimeZone(TimeZone.getTimeZone("Europe/Berlin"));
            System.out.println(sdf2.format(new Date()));
        }
    }
    

    Output:

    2020-09-27 18:38:04 +0200
    

    A piece of advice:

    I recommend you switch from the outdated and error-prone java.util date-time API and SimpleDateFormat to the modern java.time date-time API and the corresponding formatting API (package, java.time.format). Learn more about the modern date-time API from Trail: Date Time. If 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.

    Using the modern date-time API:

    import java.time.ZoneId;
    import java.time.ZonedDateTime;
    import java.time.format.DateTimeFormatter;
    
    public class Main {
        public static void main(String[] args) {
            ZonedDateTime zdt = ZonedDateTime.now(ZoneId.of("Europe/Berlin"));
    
            // Default format
            System.out.println(zdt);
    
            // Some custom format
            System.out.println(zdt.format(DateTimeFormatter.ofPattern("EEEE dd uuuu hh:mm:ss a z")));
        }
    }
    

    Output:

    2020-09-27T18:42:53.620168+02:00[Europe/Berlin]
    Sunday 27 2020 06:42:53 pm CEST
    

    The modern API will alert you whereas legacy API may failover:

    import java.time.ZoneId;
    import java.time.ZonedDateTime;
    
    public class Main {
        public static void main(String[] args) {
            ZonedDateTime zdt = ZonedDateTime.now(ZoneId.of("CEST"));
            // ...
        }
    }
    

    Output:

    Exception in thread "main" java.time.zone.ZoneRulesException: Unknown time-zone ID: CEST
        at java.base/java.time.zone.ZoneRulesProvider.getProvider(ZoneRulesProvider.java:279)
        at java.base/java.time.zone.ZoneRulesProvider.getRules(ZoneRulesProvider.java:234)
        at java.base/java.time.ZoneRegion.ofId(ZoneRegion.java:120)
        at java.base/java.time.ZoneId.of(ZoneId.java:408)
        at java.base/java.time.ZoneId.of(ZoneId.java:356)
        at Main.main(Main.java:6)
    

    As you can see, you get an exception in this case whereas SimpleDateFormat will give you undesirable result as shown below:

    import java.text.SimpleDateFormat;
    import java.util.Date;
    import java.util.TimeZone;
    
    public class Main {
        public static void main(String[] args) {
            SimpleDateFormat sdf2 = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss Z");
            sdf2.setTimeZone(TimeZone.getTimeZone("CEST"));
            System.out.println(sdf2.format(new Date()));
        }
    }
    

    Output:

    2020-09-27 16:47:45 +0000
    

    You might be wondering what this undesirable result refers to. The answer is: when SimpleDateFormat doesn't understand a time-zone, it failovers (defaults) to GMT (same as UTC) i.e. it has ignored CEST and applied GMT in this case (not a good feature IMHO 😊).