Java SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'") gives timezone as IST
Asked Answered
W

9

208

I have SimpleDateFormat constructor as

SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'")

and I am parsing string "2013-09-29T18:46:19Z".

I have read that here Z represents the GMT/UTC timezone. but when I print this date on console , It prints IST timezne for the returned date.

Now my question is whether my output is right or wrong?

Windsail answered 1/10, 2013 at 9:18 Comment(3)
yes that is what 'Z' represents. Z- Time ZoneFactual
Z = Zulu time => GMT+0, you obviously didn't serve your country ;)Scrivener
Please consider changing the accepted answer to that of "AZ_" (== using Instant). If there is library support for this exact use case, why do extra magic?Dysart
A
335

You haven't set the timezone only added a Z to the end of the date/time, so it will look like a GMT date/time but this doesn't change the value.

Set the timezone to GMT and it will be correct.

SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'");
sdf.setTimeZone(TimeZone.getTimeZone("GMT"));
Approximation answered 1/10, 2013 at 11:41 Comment(4)
If you have a date, say 2012-12-06T06:00:00 without the Z, does that represent GMT?Swinger
@Swinger You would have to ask those who sent it. It could be the local time of the sender.Approximation
Timezone can be set to "UTC"Lamprophyre
Instead of setting the timezone in so many places for different libraries and avoid conflicts with your machine/laptop timezone, you should always set the default timezone of the JVM by setting user.timezone system property: java -Duser.timezone=GMT ...Bootlace
B
124

'T' and 'Z' are considered here as constants. You need to pass Z without the quotes. Moreover you need to specify the timezone in the input string.

Example : 2013-09-29T18:46:19-0700 And the format as "yyyy-MM-dd'T'HH:mm:ssZ"

Bodega answered 1/10, 2013 at 9:23 Comment(3)
Subir, Thanks for your answer, but what is "0700" appended to input string??Windsail
-0700 is the time zone ie -7:00 HrsBodega
for -07:00 hour and not -0700 it would be the following: yyyy-MM-dd'T'HH:mm:ss.SSSXXXTomlinson
S
65

From ISO 8601 String to Java Date Object

SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'");
sdf.setTimeZone(TimeZone.getTimeZone("GMT"));
sdf.parse("2013-09-29T18:46:19Z"); //prints-> Mon Sep 30 02:46:19 CST 2013

if you don't set TimeZone.getTimeZone("GMT") then it will output Sun Sep 29 18:46:19 CST 2013

From Java Date Object to ISO 8601 String

And to convert Dateobject to ISO 8601 Standard (yyyy-MM-dd'T'HH:mm:ss'Z') use following code

SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'", Locale.US);
sdf.setTimeZone(TimeZone.getTimeZone("GMT"));           
System.out.println(sdf.format(new Date())); //-prints-> 2015-01-22T03:23:26Z

Also note that without ' ' at Z yyyy-MM-dd'T'HH:mm:ssZ prints 2015-01-22T03:41:02+0000

Soniasonic answered 22/1, 2015 at 3:29 Comment(1)
It gives me java.text.ParseException: Unparseable date: "2018-05-01T18:30:00.000Z" @SoniasonicElector
R
55

IF you want to handle 'standard' JSON representation of the Date then better to use this pattern: "yyyy-MM-dd'T'HH:mm:ssX".

Notice the X on the end. It will handle timezones in ISO 8601 standard, and ISO 8601 is exactly what produces this statement in Javascript new Date().toJSON()

Comparing to other answers it has some benefits:

  1. You don't need to require your clients to send date in GMT
  2. You don't need to explicitly convert your Date object to GMT using this: sdf.setTimeZone(TimeZone.getTimeZone("GMT"));
Rosinarosinante answered 7/4, 2015 at 22:12 Comment(3)
I am using play's automatic form binding, and use @Format.DateTime annotation. Use default pattern with Z at ending seem be incorrect. After changed to X, it works. Many thanksNickelous
If your date specifies the timezone in an RFC822-compliant fashion like "-0500", this works fine. But for a date such as "2013-07-15T10:22:17-05:00" (also valid ISO8601 TZ) this breaks. In that case you need to use "yyyy-MM-dd'T'HH:mm:ssXXX".Vanegas
"yyyy-MM-dd'T'HH:mm:ssX" should be the exact answer. 2013-09-29T18:46:19Z is ok. 'Z' = UTC = +00 = +0000=+00:00Moreen
S
40

tl;dr

The other Answers are outmoded as of Java 8.

Instant                           // Represent a moment in UTC. 
.parse( "2013-09-29T18:46:19Z" )  // Parse text in standard ISO 8601 format where the `Z` means UTC, pronounces “Zulu”.
.atZone(                          // Adjust from UTC to a time zone. 
    ZoneId.of( "Asia/Kolkata" )
)                                 // Returns a `ZonedDateTime` object. 

ISO 8601

Your string format happens to comply with the ISO 8601 standard. This standard defines sensible formats for representing various date-time values as text.

java.time

The old java.util.Date/.Calendar and java.text.SimpleDateFormat classes have been supplanted by the java.time framework built into Java 8 and later. See Tutorial. Avoid the old classes as they have proven to be poorly designed, confusing, and troublesome.

Part of the poor design in the old classes has bitten you, where the toString method applies the JVM's current default time zone when generating a text representation of the date-time value that is actually in UTC (GMT); well-intentioned but confusing.

The java.time classes use ISO 8601 formats by default when parsing/generating textual representations of date-time values. So no need to specify a parsing pattern.

An Instant is a moment on the timeline in UTC.

Instant instant = Instant.parse( "2013-09-29T18:46:19Z" );

You can apply a time zone as needed to produce a ZonedDateTime object.

ZoneId zoneId = ZoneId.of( "America/Montreal" );
ZonedDateTime zdt = instant.atZone( zoneId );

Table of date-time types in Java, both modern and legacy

Shelba answered 9/3, 2016 at 7:5 Comment(0)
N
34

and if you don't have the option to go on java8 better use 'yyyy-MM-dd'T'HH:mm:ssXXX' as this gets correctly parsed again (while with only one X this may not be the case... depending on your parsing function)

X generates: +01

XXX generates: +01:00

Normi answered 15/2, 2017 at 15:20 Comment(1)
This really helpful. I'm using the date with this format 2021-04-25T11:12:45+00:00 and this XXX has helped :)Courson
C
10

'Z' is not the same as Z

'Z' is just a character literal whereas Z is the timezone designator for zero-timezone offset. It stands for Zulu and specifies the Etc/UTC timezone (which has the timezone offset of +00:00 hours).

Therefore, do not use 'Z' in pattern for parsing/formatting.

The java.time, the modern Date-Time API

The modern Date-Time API is based on ISO 8601 and does not require using a DateTimeFormatter object explicitly as long as the Date-Time string conforms to the ISO 8601 standards. The Date-Time string, 2013-09-29T18:46:19Z conforms to ISO 8601 standards.

Demo:

import java.time.Instant;
import java.time.OffsetDateTime;
import java.time.ZonedDateTime;

public class Main {
    public static void main(String[] args) {
        Instant instant = Instant.parse("2013-09-29T18:46:19Z");
        OffsetDateTime odt = OffsetDateTime.parse("2013-09-29T18:46:19Z");
        ZonedDateTime zdt = ZonedDateTime.parse("2013-09-29T18:46:19Z");

        System.out.println(instant);
        System.out.println(odt);
        System.out.println(zdt);
    }
}

Output:

2013-09-29T18:46:19Z
2013-09-29T18:46:19Z
2013-09-29T18:46:19Z

ONLINE DEMO

An Instant represents an instantaneous point on the timeline in UTC. The Z in the output is the timezone designator for a zero-timezone offset. It stands for Zulu and specifies the Etc/UTC timezone (which has the timezone offset of +00:00 hours).

Note#1: In case you need to find out what date and time an Instant represents in a particular timezone, you can use Instant#atZone e.g. the following code will print the date and time this Instant in India:

ZonedDateTime zdtIndia = instant.atZone(ZoneId.of("Asia/Kolkata"));
System.out.println(zdtIndia);

You can even convert an object of ZonedDateTime from one timezone to another using ZonedDateTime#withZoneSameInstant e.g. the following code will convert zdt to an object of ZonedDateTime representing date and time in India:

ZonedDateTime zdtIndia = zdt.withZoneSameInstant(ZoneId.of("Asia/Kolkata"));
System.out.println(zdtIndia);

Note#2: For any reason, if you need to convert this object of Instant to an object of java.util.Date, you can do so as follows:

Date date = Date.from(instant);

You can even convert the object of OffsetDateTime and ZonedDateTime to an object of java.util.Date, as follows:

Date date = Date.from(odt.toInstant());

&

Date date = Date.from(zdt.toInstant());

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

Why did your java.util.Date object print the India date and time?

A java.util.Date object simply represents the number of milliseconds since the standard base time known as "the epoch", namely January 1, 1970, 00:00:00 GMT (or UTC). Since it does not hold any timezone information, its toString function applies the JVM's timezone to return a String in the format, EEE MMM dd HH:mm:ss zzz yyyy, derived from this milliseconds value. To get the String representation of the java.util.Date object in a different format and timezone, you need to use SimpleDateFormat with the desired format and the applicable timezone e.g.

SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssXXX", Locale.ENGLISH);
sdf.setTimeZone(TimeZone.getTimeZone("Asia/Kolkata"));
String strDate = sdf.format(date);
System.out.println(strDate);

Demo:

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

public class Main {
    public static void main(String[] args) throws ParseException {
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssXXX", Locale.ENGLISH);
        Date date = sdf.parse("2013-09-29T18:46:19Z");

        // In JVM's timezone and default format as returned by Date#toString
        System.out.println(date);

        // In UTC and custom format
        sdf.setTimeZone(TimeZone.getTimeZone("Etc/UTC"));
        String strDate = sdf.format(date);
        System.out.println(strDate);

        // In India and custom format
        sdf.setTimeZone(TimeZone.getTimeZone("Asia/Kolkata"));
        strDate = sdf.format(date);
        System.out.println(strDate);
    }
}

Output (my timezone is Europe/London):

Sun Sep 29 19:46:19 BST 2013
2013-09-29T18:46:19Z
2013-09-30T00:16:19+05:30

ONLINE DEMO


* 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.

Chiffon answered 12/6, 2021 at 21:16 Comment(0)
B
5

For Java 8: You can use inbuilt java.time.format.DateTimeFormatter to reduce any chance of typos, like

DateTimeFormatter formatter = DateTimeFormatter.ISO_ZONED_DATE_TIME;

ISO_ZONED_DATE_TIME represents 2011-12-03T10:15:30+01:00[Europe/Paris] is one of the bundled standard DateTime formats provided by Oracle link

Beano answered 8/5, 2020 at 10:51 Comment(2)
On Android, this needs the app to run above API 26Nielson
@RocBoronat Or desugaring. Or ThreeTenABP. It's certainly worth considering for lower API levels too.Wigging
F
3

Reference Examples of existing formatters:

String date1 = "2022-06-19T01:26:05.000+00:00"; 
// internally using DateTimeFormatter.ISO_OFFSET_DATE_TIME
System.out.println(OffsetDateTime.parse(date1));

//internally using DateTimeFormatter.ISO_ZONED_DATE_TIME
System.out.println(ZonedDateTime.parse(date1));

String date2 = "2022-06-19T01:26:05"; 
//internally using DateTimeFormatter.ISO_LOCAL_DATE_TIME)
System.out.println(LocalDateTime.parse(date2)); 

String date3 = "2022-06-19T01:26:05.00Z"; 
//internally using DateTimeFormatter.ISO_INSTANT
System.out.println(Instant.parse(date3));

Output:

2022-06-19T01:26:05Z
2022-06-19T01:26:05Z
2022-06-19T01:26:05
2022-06-19T01:26:05Z
Farrahfarrand answered 23/6, 2022 at 8:10 Comment(0)

© 2022 - 2025 — McMap. All rights reserved.