I have receiving a date in UTC format but needed to display it in my local timezone (EDT).
Stumbled across the following link :
How to set time zone of a java.util.Date?
Which provide this following answer :
SimpleDateFormat isoFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss");
isoFormat.setTimeZone(TimeZone.getTimeZone("UTC"));
Date date = isoFormat.parse("2010-05-23T09:01:02");
I added the following line of code :
isoFormat.setTimeZone(TimeZone.getTimeZone("UTC"));
And what do you know it worked.
Trying to understand what happened and it seems a bit backwards.
I would have expected to have to enter EDT to convert from UTC to EDT but it appears to be the opposite.
isoFormat.setTimeZone(TimeZone.getTimeZone("EDT"));
Per the Java Docs for DateFormat it reads ....
And based on the above, it seems like I should be providing the TimeZone I want and not what I am converting from.
Can you explain what am I missing or misinterpreting?
If I enter in UTC, how is it getting EDT to know to convert it correct?
Can anyone fill in the blanks on how I should have know they were asking for the "From" TimeZone?
tl;dr
Use java.time classes.
LocalDateTime
.parse( "2021-07-23T00:00" )
.atOffset( ZoneOffset.UTC )
.atZoneSameInstant( ZoneId.of( "America/Montreal" ) )
.format(
DateTimeFormatter
.ofLocalizedDateTime( FormatStyle.FULL )
.withLocale( Locale.CANADA_FRENCH )
)
Details
You are using terrible date-time classes that were years ago supplanted by the modern java.time classes.
Apparently your input strings are in standard ISO 8601 format. The java.time classes use ISO 8601 formats by default when parsing or generating text. So no need to define a custom formatting pattern.
String input = "2021-07-23T01:23:45" ;
LocalDateTime ldt = LocalDateTime.parse( input ) ;
Apparently you know for certain that the input was meant to be seen as a date and time in UTC, that is, having an offset-from-UTC of zero hours-minutes-seconds. If so, educate them publisher of your data to convince them to supply that string with a +00:00 or Z on the end to express that intention.
Meanwhile, we can assign an offset of zero to instantiate a OffsetDateTime.
OffsetDateTime odt = ldt.atOffset( ZoneOffset.UTC ) ;
And you apparently want to adjust that date-time to a particular time zone. Apply a ZoneId to get a ZonedDateTime object.
You asked for EDT. Unfortunately, such 2-4 letter codes are not a real time zone. Real time zone names are in format of Continent/Region such as Europe/Paris. Perhaps you meant a time zone such as America/New_York.
ZoneId z = ZoneId.of( "America/New_York" ) ;
ZonedDateTime zdt = odt.atZoneSameInstant( z ) ;
A java.util.Date object simply represents an instant on the timeline — a wrapper around the number of milliseconds since the UNIX epoch (January 1, 1970, 00:00:00 GMT). 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.
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 isoFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss", Locale.ENGLISH);
isoFormat.setTimeZone(TimeZone.getTimeZone("Etc/UTC"));
Date date = isoFormat.parse("2010-05-23T09:01:02");
isoFormat.setTimeZone(TimeZone.getTimeZone("Etc/UTC"));
String strDateUtc = isoFormat.format(date);
System.out.println(strDateUtc);
isoFormat.setTimeZone(TimeZone.getTimeZone("America/New_York"));
String strDateNewYork = isoFormat.format(date);
System.out.println(strDateNewYork);
}
}
Output:
2010-05-23T09:01:02
2010-05-23T05:01:02
ONLINE DEMO
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:
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.
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.ZonedDateTime;
public class Main {
public static void main(String[] args) {
LocalDateTime ldt = LocalDateTime.parse("2010-05-23T09:01:02");
ZonedDateTime zdtUtc = ldt.atZone(ZoneId.of("Etc/UTC"));
System.out.println(zdtUtc);
ZonedDateTime zdtNewYork = zdtUtc.withZoneSameInstant(ZoneId.of("America/New_York"));
System.out.println(zdtNewYork);
}
}
Output:
2010-05-23T09:01:02Z[Etc/UTC]
2010-05-23T05:01:02-04:00[America/New_York]
ONLINE DEMO
Note: For any reason, if you need to convert this object of ZonedDateTime to an object of java.util.Date, you can do so as follows:
Date date = Date.from(zdtUtc.toInstant());
or
Date date = Date.from(zdtNewYork.toInstant());
Learn more about the modern Date-Time API from Trail: Date Time.
* 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.
First thing Java doesn't support EDT abbreviation instead use "EST5EDT". If something is not found it falls EST5EDT.
You can check full list of available timezones
In SimpleDateFormatter if you are using parse() it means you trying to read "from" something. If you are using format() it means you are trying to write "to" something.
Conclusion, In the case of parse() timezone act as input format but in case of format() it acts as output format. The below program converts an EDT date to IST date. Probably using the comments in the below example you will understand what exactly is happening.
// EDT Formatter
SimpleDateFormat edtFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss");
edtFormat.setTimeZone(TimeZone.getTimeZone("EST5EDT"));
// IST Formatter
SimpleDateFormat istFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss");
istFormat.setTimeZone(TimeZone.getTimeZone("IST"));
// Convert EDT to IST
String edtDate = "2010-05-23T00:00:00";
Date date = edtFormat.parse(edtDate); //Parse from EDT to Local Timezone
String istDate = istFormat.format(date); //Parse from Local Timezone to IST
System.out.println("EDT: "+edtDate);
System.out.print("Local Date: ");
System.out.println(date);
System.out.println("IST: "+istDate);
I understand java's inital release of java.util.Date was very badly designed which created a lot of confusion that is why later they introduced java.time api whose name are way clear like LocalDate, ZonedDate etc.
Related
I tried to use
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'", Locale.ENGLISH);
LocalDate date = LocalDate.parse(d.toString(), formatter);
but it throws an error.
Is there any way to convert the JSON default timestamp?
You need to use LocalDateTime.
DateTimeFormatter formatter =
DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'", Locale.ENGLISH);
LocalDateTime date = LocalDateTime.parse(d.toString(), formatter);
You do not need DateTimeFormatter to parse your date-time string
Parse the given date string directly to OffsetDateTime. 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 Z in your date-time string 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).
OffsetDateTime odt = OffsetDateTime.parse("2020-12-20T00:00:00.000Z");
Convert the OffsetDateTime into Instant
Convert the OffsetDateTime into Instant using OffsetDateTime#toInstant. An Instant represents an instantaneous point on the timeline. It is independent of a timezone and thus, it is always in UTC.
Instant instant = odt.toInstant();
Stop using the legacy date-time API
With the release of Java SE 8 in March 2014, the outdated and error-prone legacy date-time API (java.util date-time types and their formatting type, SimpleDateFormat etc.) was supplanted by java.time, the modern date-time API*. It is strongly recommended to stop using the legacy API and switch to this new API. If at all, you need java.util.Date, get it using java.util.Date#from(Instant).
java.util.Date date = Date.from(instant);
Note that the java.util.Date object is not a real date-time object like the modern date-time types; rather, it represents the number of milliseconds since the standard base time known as "the epoch", namely January 1, 1970, 00:00:00 GMT (or UTC). When you print an object of java.util.Date, its toString method returns the date-time in the JVM's timezone, calculated from this milliseconds value. If you need to print the date-time in a different timezone, you will need to set the timezone to SimpleDateFormat and obtain the formatted string from it e.g.
Date date = new Date();
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSXXX", Locale.ENGLISH);
sdf.setTimeZone(TimeZone.getTimeZone("America/New_York"));
System.out.println(sdf.format(date));
You can convert an Instant to other date-time types
You can convert an Instant to other date-time types easily e.g. if you want to convert it into a ZonedDateTime instance representing the date-time in London, you can do so as
ZonedDateTime zdt = instant.atZone(ZoneId.of("Europe/London"));
LocalDateTime is useless in your case
Quoted below is a very good description of the uses of LocalDateTime:
This class can be used to represent a specific event, such as the
first race for the Louis Vuitton Cup Finals in the America's Cup
Challenger Series, which began at 1:10 p.m. on August 17, 2013. Note
that this means 1:10 p.m. in local time.
The best use of your date-time string is as an OffsetDateTime which you have obtained in the first step itself.
Demo:
import java.time.Instant;
import java.time.LocalDateTime;
import java.time.OffsetDateTime;
import java.time.ZoneId;
import java.time.ZoneOffset;
import java.time.ZonedDateTime;
import java.util.Date;
public class Main {
public static void main(String[] args) {
// Parse the date-time string into OffsetDateTime
OffsetDateTime odt = OffsetDateTime.parse("2020-12-20T00:00:00.000Z");
System.out.println(odt);
// Convert OffsetDateTime into Instant
Instant instant = odt.toInstant();
// If at all, you need java.util.Date
Date date = Date.from(instant);
System.out.println(date);
// You can convert an `Instant` to other date-time types easily
// e.g. to ZoneDateTime in a specific timezone
ZonedDateTime zdt = instant.atZone(ZoneId.of("Europe/London"));
System.out.println(zdt);
// e.g. to OffsetDateTime with a specific timezone offset
OffsetDateTime odt0530 = instant.atOffset(ZoneOffset.of("-05:30"));
System.out.println(odt0530);
// e.g. to LocalDateTime via an OffsetDateTime or a ZonedDateTime
LocalDateTime ldt = odt.toLocalDateTime();
System.out.println(ldt);
}
}
Output:
2020-12-20T00:00Z
Sun Dec 20 00:00:00 GMT 2020
2020-12-20T00:00Z[Europe/London]
2020-12-19T18:30-05:30
2020-12-20T00:00
Learn more about java.time, the modern date-time API* from Trail: Date Time.
* 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.
The Z is the Zulu time-zone (i.e. the UTC time-zone), not a literal Z.
This whole format is the ISO-8601 instant format.
There is a pre-existing formatter for that: DateTimeFormatter#ISO_INSTANT
Extract from the javadoc:
public static final DateTimeFormatter ISO_INSTANT
The ISO instant formatter that formats or parses an instant in UTC, such as '2011-12-03T10:15:30Z'.
This returns an immutable formatter capable of formatting and parsing the ISO-8601 instant format. When formatting, the second-of-minute is always output. The nano-of-second outputs zero, three, six or nine digits digits as necessary. When parsing, time to at least the seconds field is required. Fractional seconds from zero to nine are parsed. The localized decimal style is not used.
This is a special case formatter intended to allow a human readable form of an Instant. The Instant class is designed to only represent a point in time and internally stores a value in nanoseconds from a fixed epoch of 1970-01-01Z. As such, an Instant cannot be formatted as a date or time without providing some form of time-zone. This formatter allows the Instant to be formatted, by providing a suitable conversion using ZoneOffset.UTC.
The format consists of:
The ISO_OFFSET_DATE_TIME where the instant is converted from ChronoField.INSTANT_SECONDS and ChronoField.NANO_OF_SECOND using the UTC offset. Parsing is case insensitive.
The returned formatter has no override chronology or zone. It uses the STRICT resolver style.
This seems to be default format, please try this one.
ZonedDateTime dateTime = ZonedDateTime.parse("2020-07-28T14:28:52.877Z");
// In case you still need LocalDateTime
LocalDateTime localDateTime = dateTime.toLocalDateTime();
To your question on how to convert LocalDate to java.util.Date, you can use Date.from method as follows. Let me know if that is what you are expecting to achieve.
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'", Locale.ENGLISH);
LocalDate localDate = LocalDate.parse("2020-12-20T00:00:00.000Z", formatter);
Date date = Date.from(localDate.atStartOfDay(ZoneId.systemDefault()).toInstant());
System.out.println(date);
I have parsed a java.util.Date from a String but it is setting the local time zone as the time zone of the date object.
The time zone is not specified in the String from which Date is parsed. I want to set a specific time zone of the date object.
How can I do that?
Use DateFormat. For example,
SimpleDateFormat isoFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss");
isoFormat.setTimeZone(TimeZone.getTimeZone("UTC"));
Date date = isoFormat.parse("2010-05-23T09:01:02");
Be aware that java.util.Date objects do not contain any timezone information by themselves - you cannot set the timezone on a Date object. The only thing that a Date object contains is a number of milliseconds since the "epoch" - 1 January 1970, 00:00:00 UTC.
As ZZ Coder shows, you set the timezone on the DateFormat object, to tell it in which timezone you want to display the date and time.
tl;dr
…parsed … from a String … time zone is not specified … I want to set a specific time zone
LocalDateTime.parse( "2018-01-23T01:23:45.123456789" ) // Parse string, lacking an offset-from-UTC and lacking a time zone, as a `LocalDateTime`.
.atZone( ZoneId.of( "Africa/Tunis" ) ) // Assign the time zone for which you are certain this date-time was intended. Instantiates a `ZonedDateTime` object.
No Time Zone in j.u.Date
As the other correct answers stated, a java.util.Date has no time zone†. It represents UTC/GMT (no time zone offset). Very confusing because its toString method applies the JVM's default time zone when generating a String representation.
Avoid j.u.Date
For this and many other reasons, you should avoid using the built-in java.util.Date & .Calendar & java.text.SimpleDateFormat. They are notoriously troublesome.
Instead use the java.time package bundled with Java 8.
java.time
The java.time classes can represent a moment on the timeline in three ways:
UTC (Instant)
With an offset (OffsetDateTime with ZoneOffset)
With a time zone (ZonedDateTime with ZoneId)
Instant
In java.time, the basic building block is Instant, a moment on the time line in UTC. Use Instant objects for much of your business logic.
Instant instant = Instant.now();
OffsetDateTime
Apply an offset-from-UTC to adjust into some locality’s wall-clock time.
Apply a ZoneOffset to get an OffsetDateTime.
ZoneOffset zoneOffset = ZoneOffset.of( "-04:00" );
OffsetDateTime odt = OffsetDateTime.ofInstant( instant , zoneOffset );
ZonedDateTime
Better is to apply a time zone, an offset plus the rules for handling anomalies such as Daylight Saving Time (DST).
Apply a ZoneId to an Instant to get a ZonedDateTime. Always specify a proper time zone name. Never use 3-4 abbreviations such as EST or IST that are neither unique nor standardized.
ZoneId zoneId = ZoneId.of( "America/Montreal" );
ZonedDateTime zdt = ZonedDateTime.ofInstant( instant , zoneId );
LocalDateTime
If the input string lacked any indicator of offset or zone, parse as a LocalDateTime.
If you are certain of the intended time zone, assign a ZoneId to produce a ZonedDateTime. See code example above in tl;dr section at top.
Formatted Strings
Call the toString method on any of these three classes to generate a String representing the date-time value in standard ISO 8601 format. The ZonedDateTime class extends standard format by appending the name of the time zone in brackets.
String outputInstant = instant.toString(); // Ex: 2011-12-03T10:15:30Z
String outputOdt = odt.toString(); // Ex: 2007-12-03T10:15:30+01:00
String outputZdt = zdt.toString(); // Ex: 2007-12-03T10:15:30+01:00[Europe/Paris]
For other formats use the DateTimeFormatter class. Generally best to let that class generate localized formats using the user’s expected human language and cultural norms. Or you can specify a particular format.
About java.time
The java.time framework is built into Java 8 and later. These classes supplant the troublesome old legacy date-time classes such as java.util.Date, Calendar, & SimpleDateFormat.
To learn more, see the Oracle Tutorial. And search Stack Overflow for many examples and explanations. Specification is JSR 310.
The Joda-Time project, now in maintenance mode, advises migration to the java.time classes.
You may exchange java.time objects directly with your database. Use a JDBC driver compliant with JDBC 4.2 or later. No need for strings, no need for java.sql.* classes. Hibernate 5 & JPA 2.2 support java.time.
Where to obtain the java.time classes?
Java SE 8, Java SE 9, Java SE 10, Java SE 11, and later - Part of the standard Java API with a bundled implementation.
Java 9 brought some minor features and fixes.
Java SE 6 and Java SE 7
Most of the java.time functionality is back-ported to Java 6 & 7 in ThreeTen-Backport.
Android
Later versions of Android (26+) bundle implementations of the java.time classes.
For earlier Android (<26), a process known as API desugaring brings a subset of the java.time functionality not originally built into Android.
If the desugaring does not offer what you need, the ThreeTenABP project adapts ThreeTen-Backport (mentioned above) to Android. See How to use ThreeTenABP….
Joda-Time
While Joda-Time is still actively maintained, its makers have told us to migrate to java.time as soon as is convenient. I leave this section intact as a reference, but I suggest using the java.time section above instead.
In Joda-Time, a date-time object (DateTime) truly does know its assigned time zone. That means an offset from UTC and the rules and history of that time zone’s Daylight Saving Time (DST) and other such anomalies.
String input = "2014-01-02T03:04:05";
DateTimeZone timeZone = DateTimeZone.forID( "Asia/Kolkata" );
DateTime dateTimeIndia = new DateTime( input, timeZone );
DateTime dateTimeUtcGmt = dateTimeIndia.withZone( DateTimeZone.UTC );
Call the toString method to generate a String in ISO 8601 format.
String output = dateTimeIndia.toString();
Joda-Time also offers rich capabilities for generating all kinds of other String formats.
If required, you can convert from Joda-Time DateTime to a java.util.Date.
Java.util.Date date = dateTimeIndia.toDate();
Search StackOverflow for "joda date" to find many more examples, some quite detailed.
†Actually there is a time zone embedded in a java.util.Date, used for some internal functions (see comments on this Answer). But this internal time zone is not exposed as a property, and cannot be set. This internal time zone is not the one used by the toString method in generating a string representation of the date-time value; instead the JVM’s current default time zone is applied on-the-fly. So, as shorthand, we often say “j.u.Date has no time zone”. Confusing? Yes. Yet another reason to avoid these tired old classes.
You could also set the timezone at the JVM level
Date date1 = new Date();
System.out.println(date1);
TimeZone.setDefault(TimeZone.getTimeZone("UTC"));
// or pass in a command line arg: -Duser.timezone="UTC"
Date date2 = new Date();
System.out.println(date2);
output:
Thu Sep 05 10:11:12 EDT 2013
Thu Sep 05 14:11:12 UTC 2013
If you must work with only standard JDK classes you can use this:
/**
* Converts the given <code>date</code> from the <code>fromTimeZone</code> to the
* <code>toTimeZone</code>. Since java.util.Date has does not really store time zome
* information, this actually converts the date to the date that it would be in the
* other time zone.
* #param date
* #param fromTimeZone
* #param toTimeZone
* #return
*/
public static Date convertTimeZone(Date date, TimeZone fromTimeZone, TimeZone toTimeZone)
{
long fromTimeZoneOffset = getTimeZoneUTCAndDSTOffset(date, fromTimeZone);
long toTimeZoneOffset = getTimeZoneUTCAndDSTOffset(date, toTimeZone);
return new Date(date.getTime() + (toTimeZoneOffset - fromTimeZoneOffset));
}
/**
* Calculates the offset of the <code>timeZone</code> from UTC, factoring in any
* additional offset due to the time zone being in daylight savings time as of
* the given <code>date</code>.
* #param date
* #param timeZone
* #return
*/
private static long getTimeZoneUTCAndDSTOffset(Date date, TimeZone timeZone)
{
long timeZoneDSTOffset = 0;
if(timeZone.inDaylightTime(date))
{
timeZoneDSTOffset = timeZone.getDSTSavings();
}
return timeZone.getRawOffset() + timeZoneDSTOffset;
}
Credit goes to this post.
java.util.Calendar is the usual way to handle time zones using just JDK classes. Apache Commons has some further alternatives/utilities that may be helpful. Edit Spong's note reminded me that I've heard really good things about Joda-Time (though I haven't used it myself).
Convert the Date to String and do it with SimpleDateFormat.
SimpleDateFormat readFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss");
readFormat.setTimeZone(TimeZone.getTimeZone("GMT" + timezoneOffset));
String dateStr = readFormat.format(date);
SimpleDateFormat writeFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss");
Date date = writeFormat.parse(dateStr);
This code was helpful in an app I'm working on:
Instant date = null;
Date sdf = null;
String formatTemplate = "EEE MMM dd yyyy HH:mm:ss";
try {
SimpleDateFormat isoFormat = new SimpleDateFormat("EEE MMM dd yyyy HH:mm:ss");
isoFormat.setTimeZone(TimeZone.getTimeZone(ZoneId.of("US/Pacific")));
sdf = isoFormat.parse(timeAtWhichToMakeAvailable);
date = sdf.toInstant();
} catch (Exception e) {
System.out.println("did not parse: " + timeAtWhichToMakeAvailable);
}
LOGGER.info("timeAtWhichToMakeAvailable: " + timeAtWhichToMakeAvailable);
LOGGER.info("sdf: " + sdf);
LOGGER.info("parsed to: " + date);
Here you be able to get date like "2020-03-11T20:16:17" and return "11/Mar/2020 - 20:16"
private String transformLocalDateTimeBrazillianUTC(String dateJson) throws ParseException {
String localDateTimeFormat = "yyyy-MM-dd'T'HH:mm:ss";
SimpleDateFormat formatInput = new SimpleDateFormat(localDateTimeFormat);
//Here is will set the time zone
formatInput.setTimeZone(TimeZone.getTimeZone("UTC-03"));
String brazilianFormat = "dd/MMM/yyyy - HH:mm";
SimpleDateFormat formatOutput = new SimpleDateFormat(brazilianFormat);
Date date = formatInput.parse(dateJson);
return formatOutput.format(date);
}
If anyone ever needs this, if you need to convert an XMLGregorianCalendar timezone to your current timezone from UTC, then all you need to do is set the timezone to 0, then call toGregorianCalendar() - it will stay the same timezone, but the Date knows how to convert it to yours, so you can get the data from there.
XMLGregorianCalendar xmlStartTime = DatatypeFactory.newInstance()
.newXMLGregorianCalendar(
((GregorianCalendar)GregorianCalendar.getInstance());
xmlStartTime.setTimezone(0);
GregorianCalendar startCalendar = xmlStartTime.toGregorianCalendar();
Date startDate = startCalendar.getTime();
XMLGregorianCalendar xmlStartTime = DatatypeFactory.newInstance()
.newXMLGregorianCalendar(startCalendar);
xmlStartTime.setHour(startDate.getHours());
xmlStartTime.setDay(startDate.getDate());
xmlStartTime.setMinute(startDate.getMinutes());
xmlStartTime.setMonth(startDate.getMonth()+1);
xmlStartTime.setTimezone(-startDate.getTimezoneOffset());
xmlStartTime.setSecond(startDate.getSeconds());
xmlStartTime.setYear(startDate.getYear() + 1900);
System.out.println(xmlStartTime.toString());
Result:
2015-08-26T12:02:27.183Z
2015-08-26T14:02:27.183+02:00
This answer is probably the shortest and it uses only the Date class:
long current = new Date().getTime() + 3_600_000; //e.g. your JVM time zone +1 hour (3600000 milliseconds)
System.out.printf("%1$td.%1$tm.%1$tY %1$tH:%1$tM\n", current);//european time format
But, if you can, use more modern ways to doing the same.
package org.example;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.TimeZone;
public class time {
public static void main(String[] args) {
SimpleDateFormat sdf=new SimpleDateFormat("yyyy/MM/dd HH:mm");
sdf.setTimeZone(TimeZone.getTimeZone("Asia/Jakarta"));
Date date=new Date();
sdf.format(date);
System.out.println(sdf.format(date));
}
}
I have two related questions.
Assume a program running in (British Standard Time)BST generates a date time value for current time in UTC (YYYY-MM-DDTHH:MM:SS.SSSZ) format.
Also assume current time in London is 2016-06-01 12:33:54.
If the current time given by the program is 2016-06-01T11:33:54.000Z , is the program wrong?
How is summertime offset for BST noted in the corresponding time format for YYYY-MM-DDTHH:MM:SS.SSSZ
I assume YYYY-MM-DDTHH:MM:SS+0001. Am I correct ?
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.
The program is correct, since the London time is one hour ahead of "UTC" time in summer
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.
if the current time given by the program is 2016-06-01T11:33:54.000Z ,
is the program wrong?
The format is correct and conforms to ISO 8601 but it does not represent Europe/London time. In London, in 2016, the DST started at Sunday, March 27, 1:00 am and ended at Sunday, October 30, 2:00 am and therefore a date-time representation for Europe/London during this time should have a timezone offset of +01:00 hours. The Z at the end specifies Zulu time which is UTC time and thus has a timezone offset of +00:00 hours. The same instant can be represented for Europe/London as 2016-06-01T12:33:54+01:00.
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 java.time, the modern date-time API* .
Even Joda-Time should not be used anymore. Notice the following note at the Home Page of Joda-Time
Joda-Time is the de facto standard date and time library for Java
prior to Java SE 8. Users are now asked to migrate to java.time
(JSR-310).
java.time API is based on ISO 8601 and the date-time string, 2016-06-01T11:33:54.000Z can be parsed into java.time.ZonedDateTime and java.time.OffsetDateTime without needing a date-time parsing/formatting type.
Demo:
import java.time.ZoneId;
import java.time.ZonedDateTime;
public class Main {
public static void main(String[] args) {
ZonedDateTime zdt = ZonedDateTime.parse("2016-06-01T11:33:54.000Z");
System.out.println(zdt);
ZoneId zoneId = ZoneId.of("Europe/London");
ZonedDateTime zdtInLondon = zdt.withZoneSameInstant(zoneId);
System.out.println(zdtInLondon);
}
}
Output:
2016-06-01T11:33:54Z
2016-06-01T12:33:54+01:00[Europe/London]
How to deal with Daylight Saving Time (DST)?
As mentioned earlier, the date-time string, 2016-06-01T11:33:54.000Z can also be parsed into java.time.OffsetDateTime without needing a date-time parsing/formatting type. However, OffsetDateTime has been designed to deal with a fixed timezone offset whereas ZonedDateTime has been designed to deal with a timezone and thus it take care of DST automatically. You can convert a ZonedDateTime to OffsetDateTime using ZonedDateTime#toOffsetDateTime if required.
import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Locale;
public class Main {
public static void main(String[] args) {
DateTimeFormatter dtf = DateTimeFormatter.ofPattern("uuuu-MM-dd'T'HH:mm:ss.SSS z", Locale.ENGLISH);
String strDateTime = "2016-03-01T11:33:54.000 Europe/London";
ZonedDateTime zdt = ZonedDateTime.parse(strDateTime, dtf);
System.out.println(zdt);
strDateTime = "2016-06-01T11:33:54.000 Europe/London";
zdt = ZonedDateTime.parse(strDateTime, dtf);
System.out.println(zdt);
}
}
Output:
2016-03-01T11:33:54Z[Europe/London]
2016-06-01T11:33:54+01:00[Europe/London]
Notice how the timezone offset has automatically changed from Z to 01:00 to reflect DST change. On the other hand,
import java.time.OffsetDateTime;
public class Main {
public static void main(String[] args) {
String strDateTime = "2016-03-01T11:33:54.000+01:00";
OffsetDateTime odt = OffsetDateTime.parse(strDateTime);
System.out.println(odt);
strDateTime = "2016-06-01T11:33:54.000+01:00";
odt = OffsetDateTime.parse(strDateTime);
System.out.println(odt);
}
}
Output:
2016-03-01T11:33:54+01:00
2016-06-01T11:33:54+01:00
In this case, you do not talk about a timezone (e.g. Europe/London); rather, you talk about a fixed timezone offset of +01:00 hours.
Learn more about the modern date-time API from Trail: Date Time.
* 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.
I have the following code:
String ModifiedDate = "1993-06-08T18:27:02.000Z" ;
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSZ");
Date ModDate = sdf.parse(ModifiedDate);
I am getting the following exception even though my date format is fine...
java.text.ParseException: Unparseable date: "1993-06-08T18:27:02.000Z"
at java.text.DateFormat.parse(DateFormat.java:337)
The Z pattern latter indicates an RFC 822 time zone. Your string
String ModifiedDate = "1993-06-08T18:27:02.000Z" ;
does not contain such a time zone. It contains a Z literally.
You'll want a date pattern, that similarly to the literal T, has a literal Z.
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'");
If you meant for Z to indicate Zulu time, add that as a timezone when constructing the SimpleDateFormat
sdf.setTimeZone(TimeZone.getTimeZone("Zulu"));;
java.time
The modern Date-Time API, released with Java-8 in March 2014, supplanted the legacy date-time API (the java.util Date-Time API and their formatting API, SimpleDateFormat). Since then, it is strongly recommended to stop using the error-prone legacy API and switch to java.time API.
Solution using java.time API: java.time API is based on ISO 8601 and therefore you do not need a DateTimeFormatter to parse a date-time string which is already in ISO 8601 format (e.g. your date-time string, 1993-06-08T18:27:02.000Z).
import java.time.Instant;
import java.time.OffsetDateTime;
import java.time.ZonedDateTime;
class Main {
public static void main(String[] args) {
String strModifiedDate = "1993-06-08T18:27:02.000Z";
Instant instant = Instant.parse(strModifiedDate);
System.out.println(instant);
// It can also be directly parsed into a ZonedDateTime
ZonedDateTime zdt = ZonedDateTime.parse(strModifiedDate);
System.out.println(zdt);
// or even into an OffsetDateTime
OffsetDateTime odt = OffsetDateTime.parse(strModifiedDate);
System.out.println(odt);
}
}
Output:
1993-06-08T18:27:02Z
1993-06-08T18:27:02Z
1993-06-08T18:27:02Z
If for any reason, you need java.util.Date instance, you can get it as follows:
Date date = Date.from(instant);
Learn more about the modern Date-Time API from Trail: Date Time.
Just for the sake of completeness:
Here is the solution using the legacy date-time API. First of all, note that 'Z' is not the same as Z. 'Z' is just a character literal whereas Z is the timezone designator for zero-timezone offset (or UTC). So, never use 'Z' in the date-time formatting/parsing pattern; otherwise, it will be interpreted merely as a literal character, and not as a timezone designator.
The correct letter to be used in the pattern for timezone offset is X.
Demo:
class Main {
public static void main(String[] args) throws ParseException {
String strModifiedDate = "1993-06-08T18:27:02.000Z";
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSX");
Date modifiedDate = sdf.parse(strModifiedDate);
System.out.println(modifiedDate);
}
}
The answer by Sotirios Delimanolis is correct. The Z means Zulu time, a zero offset from UTC (+00:00). In other words, not adjusted to any time zone.
Joda-Time
FYI, the Joda-Time library make this work much easier, as does the new java.time package in Java 8.
The format you are using is defined by the ISO 8601 standard. Joda-Time and java.time both parse & generate ISO 8601 strings by default.
A DateTime in Joda-Time knows its own assigned time zone. So as part of the process of parsing, specify a time zone to adjust.
DateTimeZone timeZone = DateTimeZone.forID( "Europe/Paris" );
DateTime dateTime = new DateTime( "1993-06-08T18:27:02.000Z", timeZone );
String output = dateTime.toString();
You can keep the DateTime object in Universal Time if desired.
DateTime dateTime = new DateTime( "1993-06-08T18:27:02.000Z", DateTimeZone.UTC );
When required by other classes, you can generate a java.util.Date object.
java.util.Date date = dateTime.toDate();
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?
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"));
'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"
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
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:
You don't need to require your clients to send date in GMT
You don't need to explicitly convert your Date object to GMT using this: sdf.setTimeZone(TimeZone.getTimeZone("GMT"));
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 );
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
'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.
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
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