Java Simpledateformat("Yyyy-Mm-Dd'T'Hh:Mm:Ss'Z'") Gives Timezone as Ist

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

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"));

SimpleDateFormat with TimeZone

Just turn your z to upperCase

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

Result: 2016-06-10T13:53:22 +0200

Why I can't parse this date format yyyy-MM-dd'T'HH:mm:ss.SSSZ?

You should use Z the same way you use T for the parser to recognize the character in format

val stringDate = "2021-12-16T16:42:00.000Z"
val sdf = SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'")
var consultationDate = sdf.parse(stringDate)

Java format yyyy-MM-dd'T'HH:mm:ss.SSSz to yyyy-mm-dd HH:mm:ss

SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss");
SimpleDateFormat output = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
Date d = sdf.parse(time);
String formattedTime = output.format(d);

This works. You have to use two SimpleDateFormats, one for input and one for output, but it will give you just what you are wanting.

yyyy-MM-dd'T'HH:mm:ss.SSSSSSS'Z' format

Milliseconds (SSS) can only be three digits. On more than that, the date rolls over - e.g. 10:38:14.1000 becomes 10:38:15.000. Add a couple of million milliseconds... and you get the behaviour that you're seeing now.

Try this.

SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS");
Date c = sdf.parse("2017-03-31T10:38:14.472Z");

System.out.println(c);

DateFormat istFormat = new SimpleDateFormat();
DateFormat gmtFormat = new SimpleDateFormat();
TimeZone gmtTime = TimeZone.getTimeZone("GMT");
TimeZone istTime = TimeZone.getTimeZone("IST");

istFormat.setTimeZone(gmtTime);
gmtFormat.setTimeZone(istTime);
System.out.println("GMT Time: " + istFormat.format(c));
System.out.println("IST Time: " + gmtFormat.format(c));

DateFormat pattern yyyy-MM-dd'T'HH:mm:ss.SSS'Z' in Gson

Quick answer

First string is correctly parsed using your date format and your local time zone, second one does not respect it, so will be parsed by a default SimpleDateFormat object that has not milliseconds ("yyyy-MM-dd'T'HH:mm:ss'Z' is the parsing format) and uses UTC timezone giving you a "shift" in time part.

Full answer

To fully respond to your question you need to dive into Gson source code. More in particular you have to look at code of DefaultDateTypeAdapter that is used to parse dates. You can find all this code at link, but for quick reference I will copy here most relevant parts.

When you call this in the builder:

gb.setDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'");

you are initializing a DefaultDateTypeAdapter in this way:

DefaultDateTypeAdapter(DateFormat enUsFormat, DateFormat localFormat) {
this.enUsFormat = enUsFormat;
this.localFormat = localFormat;
this.iso8601Format = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'", Locale.US);
this.iso8601Format.setTimeZone(TimeZone.getTimeZone("UTC"));
}

where:

  1. enUsFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'") and
  2. localFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'", Locale.US)

since the string you have passed in the builder.

Pay attention that Locale.US is not a timezone and that iso8601Format is the same as enUsFormat without milliseconds but with UTC timezone.

Parsing happens into deserializeToDate method:

 private Date deserializeToDate(JsonElement json) {
synchronized (localFormat) {
try {
return localFormat.parse(json.getAsString());
} catch (ParseException ignored) {
}
try {
return enUsFormat.parse(json.getAsString());
} catch (ParseException ignored) {
}
try {
return iso8601Format.parse(json.getAsString());
} catch (ParseException e) {
throw new JsonSyntaxException(json.getAsString(), e);
}
}
}

where all of three date formats are used in a waterfall approach.

First Json string: "2011-11-02T02:50:12.208Z". It's parsed immediately by localFormat since has milliseconds and gives you the result you expect using your timezone.

Second Json string: "1899-12-31T16:00:00Z". It won't be parsed by localFormat since has not milliseconds, so second chance is enUsFormat that is the same pattern, except for the locale. So it will fail at the same way.

Last chance to parse: iso8601Format, it will, it has no milliseconds, BUT, for construction, it as also a UTC time zone, so it will parse date as UTC while the others parsed using your timezone.

2020-04-03 20:17:46 to yyyy-MM-dd'T'HH:mm:ss format

Just for the case you are using Java 8 or above, make use of java.time.

See this simple example:

public static void main(String[] args) {
// example datetime
String datetime = "2020-04-03 20:17:46";
// create a formatter that parses datetimes of this pattern
DateTimeFormatter parserDtf = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
// then parse the datetime with that formatter
LocalDateTime ldt = LocalDateTime.parse(datetime, parserDtf);
// in order to output the parsed datetime, use the default formatter (implicitly)
System.out.println(ldt);
// or format it in a totally different way
System.out.println(ldt.format(
DateTimeFormatter.ofPattern("EEE, dd. 'of' MMM 'at' hh-mm-ss a",
Locale.ENGLISH)
)
);
}

This outputs

2020-04-03T20:17:46
Fri, 03. of Apr at 08-17-46 PM

Please note that this doesn't consider any time zone or offset, it just represents a date and time consisting of the passed or parsed years, months, days, hours, minutes and seconds, nothing else.

yyyy-MM-dd'T'HH:mm:ss.SSSSSSS'Z' convert to date format

You can just use below to parse.

SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss", Locale.getDefault());

Understanding specific UTC time format YYYY-MM-DDTHH:MM:SS.SSSZ

Firstly please have a read of the iso8601 information. It's becoming more common place to deal with times in different time zones (e.g. server time zone and client time zone) and the standard is really useful.

In particular please read about UTC or "Zulu" time here.

  1. The program is correct, since the London time is one hour ahead of "UTC" time in summer

  2. The trailing 'Z' is a short notation for UTC (Zulu). You could also write "+00:00" instead of 'Z'. The SS.SSS refer to seconds and milliseconds - not related to the time zone. In devnull's comment he shows you how to apply an offset for summer.

Edit:

There's been some discussion in the comments about whether iso8601 timezone includes timezone or not, and whether timezone will in fact be printed out.

This depends completely on the date/time implementation. If we are using SimpleDateFormat then timezone is supported and will be printed.

Here's a code example to illustrate

SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSXXX");
formatter.setTimeZone(TimeZone.getTimeZone("UTC"));
System.out.println(formatter.format(new Date()));
formatter.setTimeZone(TimeZone.getTimeZone("Europe/London"));
System.out.println(formatter.format(new Date()));

Output

2016-06-02T12:53:14.924Z
2016-06-02T13:53:14.925+01:00

Naturally, if you are using a different date/time library such as joda-time, then the implentation details will be different.

Edit: As @DerrylThomas pointed out with SimpleDateFormat wise to use lower case y for years - unless it's intended to use week year - explained in a bit of detail in another answer to a similar question https://stackoverflow.com/a/56911450.



Related Topics



Leave a reply



Submit