Following code throws the exception when try to parse from the string (2011-12-08T02:01:02+01:00):
image.setLastUpdated(new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssz")
.parse(imageElement.getAttribute("lastUpdate")))
I have also tried the following format:
image.setLastUpdated(new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssZ")
.parse(imageElement.getAttribute("lastUpdate")));
But I get the same exception:
java.text.ParseException: Unparseable date: "2011-12-08T02:01:02+01:00"
at java.text.DateFormat.parse(DateFormat.java:357)
at com.discavo.ImportManagerGiata.parseImageXML(ImportManagerGiata.java:204)
You need X as the specifier for the UTC offset as it's in ISO-8601 format, as per the SimpleDateFormat documentation.
new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssX")
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*.
Also, quoted below is a notice from the home page of Joda-Time:
Note that from Java SE 8 onwards, users are asked to migrate to java.time (JSR-310) - a core part of the JDK which replaces this project.
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. Your Date-Time string conforms to the ISO 8601 format.
Demo:
import java.time.Instant;
import java.time.OffsetDateTime;
public class Main {
public static void main(String[] args) {
OffsetDateTime odt = OffsetDateTime.parse("2011-12-08T02:01:02+01:00");
System.out.println(odt);
// ########### In case you need Instant ###########
Instant instant = odt.toInstant();
System.out.println(instant);
// Java-12 onwards, you can parse the ISO-8601 compliant Date-Time with timezone
// information directly into Instant
instant = Instant.parse("2011-12-08T02:01:02+01:00");
System.out.println(instant);
}
}
Output:
2011-12-08T02:01:02+01:00
2011-12-08T01:01:02Z
2011-12-08T01:01:02Z
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: 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);
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.
The answer by Jon Skeet is correct. But FYI…
No problem in Joda-Time
The problem presented by this question does not exist if using Joda-Time rather than the mess that is the java.util.Date/Calendar classes bundled with Java.
Joda-Time 2.3 has a variety of built-in parsers, so no need to specify a format in this case. Use methods on the ISODateTimeFormat class to retrieve a variety of formatters designed to parse variations of ISO 8601 formatted strings.
The question fails to account for time zone. So I am showing all three possibilities:
You want the time converted to a specific time zone.Denver in this example.
You want the time adjusted to UTC, for no time offset.Common for storage or further date-time work.
You want to preserve this date-time with its offset.Not usually a good idea, as you have neither the benefit of UTC (no offset and no need to worry about Daylight Saving Time DST or other issues), nor the benefit of a named time zone with rules to handle DST or other issues.
For Desired Time Zone
// For desired time zone. Arbitrarily using 'Denver' as named time zone for this example.
DateTimeZone denverTimeZone = DateTimeZone.forID( "America/Denver" );
org.joda.time.DateTime dateTimeInDenver = org.joda.time.format.ISODateTimeFormat.dateTimeNoMillis().withZone(denverTimeZone).parseDateTime( "2011-12-08T02:01:02+01:00" );
System.out.println( "dateTimeInDenver: " + dateTimeInDenver );
When run…
dateTimeInDenver: 2011-12-07T18:01:02.000-07:00
For UTC
// For UTC (no offset).
org.joda.time.DateTime dateTimeInUTC = org.joda.time.format.ISODateTimeFormat.dateTimeNoMillis().withZoneUTC().parseDateTime( "2011-12-08T02:01:02+01:00" );
System.out.println( dateTimeInUTC );
When run…
2011-12-08T01:01:02.000Z
For Offset As Parsed
// For offset as parsed.
// Least beneficial, as no rules for Daylight Saving Time (DST) or other anomalies can be applied.
org.joda.time.DateTime dateTimeWithOffsetParsed = org.joda.time.format.ISODateTimeFormat.dateTimeNoMillis().withOffsetParsed().parseDateTime( "2011-12-08T02:01:02+01:00" );
System.out.println( "dateTimeWithOffsetParsed: " + dateTimeWithOffsetParsed );
When run…
dateTimeWithOffsetParsed: 2011-12-08T02:01:02.000+01:00
Related
I am trying to convert IST to UTC epoch in Java
But instead of subtracting 5.30 hours from IST, it adds 5.30 in IST
public static long convertDateToEpochFormat(String date) {
Date convertedDate = null;
try {
LOGGER.info(date);
DateFormat formatter = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
formatter.setTimeZone(TimeZone.getTimeZone("UTC"));
LOGGER.info(date);
convertedDate = formatter.parse(date);
LOGGER.info(convertedDate);
} catch (ParseException e) {
e.printStackTrace();
}
return convertedDate.getTime() / 1000L;
}
The log statements I obtained is :
2017-01-01 00:00:00
2017-01-01 00:00:00
Sun Jan 01 05:30:00 IST 2017
It should ideally be Dec 31 18:30:00 because of UTC conversion.
Can anyone tell me whats wrong ?
tl;dr
Why does util.Date forwards the date instead of subtracting it?
Because India time is ahead of UTC, not behind.
Instant.parse(
"2017-01-01 00:00:00".replace( " " , "T" ) + "Z"
).atZone(
ZoneId.of( "Asia/Kolkata" )
).toString()
2017-01-01T05:30+05:30[Asia/Kolkata]
Using java.time
You are using troublesome old date-time classes that are now legacy, supplanted by the java.time classes.
ISO 8601
Your input string is almost in standard ISO 8601 format. To comply fully, replace that SPACE in the middle with a T. The java.time classes use standard formats when parsing/generating strings. So no need to specify a formatting pattern.
String input = "2017-01-01 00:00:00".replace( " " , "T" ) ;
If that input is meant to represent a moment in UTC, append a Z, short for Zulu, means UTC.
String input = "2017-01-01 00:00:00".replace( " " , "T" ) + "Z" ; // Assuming this input was intended to be in UTC.
2017-01-01T00:00:00Z
When possible, just use the ISO 8601 formats in the first place when serializing date-time values to strings.
Instant
Parse that input string as an Instant, a moment on the timeline in UTC with a resolution of nanoseconds.
Instant instant = Instant.parse( input ) ;
instant.toString(): 2017-01-01T00:00:00Z
ZonedDateTime
You seem to want this value adjusted into India time. Apply a ZoneId to get a ZonedDateTime.
Specify a proper time zone name in the format of continent/region, such as America/Montreal, Africa/Casablanca, or Pacific/Auckland. Never use the 3-4 letter abbreviation such as EST or IST as they are not true time zones, not standardized, and not even unique(!).
ZoneId z = ZoneId.of( "Asia/Kolkata" ) ;
ZonedDateTime zdt = instant.atZone( z ) ;
zdt.toString(): 2017-01-01T05:30+05:30[Asia/Kolkata]
See this code run live at IdeOne.com.
India time is ahead of UTC
Your Question expects the India time to go backwards, behind the UTC value. This makes no sense. India time is ahead of UTC, not behind UTC. The Americas have time zones behind UTC as they lay westward. East of the Prime Meridian in Greenwich are offsets ahead of UTC. In modern times, ISO 8601 and most other protocols mark such offsets with a plus sign: +05:30. Note that some old protocols did the opposite (used a negative sign).
Midnight UTC = 5:30 AM India
So midnight in UTC, 00:00:00 at the Prime Meridian, is simultaneously five-thirty in the morning in India.
So all three of these represent the same simultaneous moment, the same point in the timeline:
2017-01-01T00:00:00Z
2017-01-01T05:30+05:30[Asia/Kolkata]
2016-12-31T16:00-08:00[America/Los_Angeles]
Avoid count-from-epoch
Do not handle time as an integer count from epoch as you are doing by returning a long from your method as seen in the Question. In your Java code pass around date-time values using date-time objects, java.time objects specifically. When passing date-time values outside your Java code, serialize to strings using the practical ISO 8601 formats.
Relying on an integer count-from-epoch values is confusing, difficult to debug, impossible to read by humans, and will lead to frustration and errors (even worse: unobserved errors).
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.
The Joda-Time project, now in maintenance mode, advises migration to the java.time classes.
To learn more, see the Oracle Tutorial. And search Stack Overflow for many examples and explanations. Specification is JSR 310.
Where to obtain the java.time classes?
Java SE 8, Java SE 9, and later
Built-in.
Part of the standard Java API with a bundled implementation.
Java 9 adds some minor features and fixes.
Java SE 6 and Java SE 7
Much of the java.time functionality is back-ported to Java 6 & 7 in ThreeTen-Backport.
Android
The ThreeTenABP project adapts ThreeTen-Backport (mentioned above) for Android specifically.
See How to use ThreeTenABP….
The ThreeTen-Extra project extends java.time with additional classes. This project is a proving ground for possible future additions to java.time. You may find some useful classes here such as Interval, YearWeek, YearQuarter, and more.
The answer by Basil Bourque is not only correct, it is also very informative. I have already upvoted it. I’ll try just a little bit of a different angle.
As I understand your question, your date-time string 2017-01-01 00:00:00 should be interpreted in IST, AKA Asia/Kolkata time, and you want to convert it to seconds (not milliseconds) since the epoch. And you are asking why you are getting an incorrect result.
I think the answer is rather banal: When the date-time string is in India time, you should not set UTC time on the formatter you use for parsing it. This is sure to get an incorrect result (if you were to format the date-time into UTC, you would do well in setting UTC as time zone on the formatter used for formatting, but this is a different story).
I agree with Basil Bourque that you should avoid the outdated classes Date and SimpleDateFormat. So here’s my suggestion (assuming you do need epoch seconds and cannot use an Instant as Basil Bourque recommends).
private static DateTimeFormatter parseFormatter = DateTimeFormatter.ofPattern("uuuu-MM-dd HH:mm:ss");
public static long convertDateToEpochFormat(String date) {
return LocalDateTime.parse(date, parseFormatter)
.atZone(ZoneId.of("Asia/Kolkata"))
.toInstant()
.getEpochSecond();
}
This will convert your example string into an instant of 2016-12-31T18:30:00Z and return 1483209000. Please check for yourself that it is correct.
I have been assuming all the way that by IST you meant Indian Standard Time. Please be aware that three and four letter time zone abbreviations are ambiguous. For example, my JVM thinks that IST means Israel Standard Time. If you intended the same, please substitute Asia/Jerusalem for Asia/Kolkata. If you meant Irish Standard Time (another recognized/semi-official interpretation), please use Europe/Dublin. You will of course get different output in each case.
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 was looking for a way to get current time in various timezones based on an user input. I know I could use Joda Time! but is that the only way?
Isn't there an option in Java for doing this? I tried the following code which gives the same output for all 3 sysouts.
Calendar pst = Calendar.getInstance(TimeZone.getTimeZone("PST"));
System.out.println("PST " + pst.getTime());
Calendar ist = Calendar.getInstance(TimeZone.getTimeZone("Asia/Calcutta"));
System.out.println("IST " + ist.getTime());
Calendar utc = Calendar.getInstance(TimeZone.getTimeZone("Etc/UTC"));
System.out.println("UCT " + utc.getTime());
What am I missing here to get current time in other timezones?
Yes, that would show the same value in every case (or milliseconds apart) because the three calendars all refer to the same instant in time (execution time notwithstanding) and that's all that a java.util.Date represents. That's the result of Calendar.getTime().
However, the Calendar itself does know about time zones, and that will be reflected when you use Calendar.get etc. It will also be used when you use a SimpleDateFormat, where you can specify a particular time zone.
// Specify whatever format you want - bear in mind different locales etc
SimpleDateFormat format = new SimpleDateFormat("dd/MM/yyyy HH:mm:ss");
format.setTimeZone(calendar.getTimeZone());
String text = format.format(calendar.getTime());
It's not clear exactly what you're trying to do, but basically you need to be aware of which types are time zone aware, and which aren't. It's really important to understand that a java.util.Date doesn't have a format, a calendar system or a time zone: it's just the number of milliseconds since the Unix epoch.
As Jon pointed out the method getTime() is returning a java.util.Date object which is just a millisecond value and not timezone aware.
If you are just looking at printing the times then you can use the calendar and manually get the fields you want like
System.out.println(utc.get(Calendar.HOUR_OF_DAY) + ":" + utc.get(Calendar.MINUTE))
This would need some formatting for a minute < 10 to display the 0
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*.
Also, quoted below is a notice from the home page of Joda-Time:
Note that from Java SE 8 onwards, users are asked to migrate to java.time (JSR-310) - a core part of the JDK which replaces this project.
Solution using java.time, the modern Date-Time API:
import java.time.Instant;
import java.time.ZoneId;
import java.time.ZoneOffset;
import java.time.ZonedDateTime;
public class Main {
public static void main(String[] args) {
Instant now = Instant.now();
System.out.println(now);
ZonedDateTime zdtLos = now.atZone(ZoneId.of("America/Los_Angeles"));
ZonedDateTime zdtIndia = now.atZone(ZoneId.of("Asia/Kolkata"));
ZonedDateTime zdtUtc = now.atZone(ZoneOffset.UTC);
System.out.println(zdtLos);
System.out.println(zdtIndia);
System.out.println(zdtUtc);
}
}
Output from a sample run:
2021-07-26T12:39:17.413671-07:00[America/Los_Angeles]
2021-07-27T01:09:17.413671+05:30[Asia/Kolkata]
2021-07-26T19:39:17.413671Z
ONLINE DEMO
An Instant represents an instantaneous point on the timeline, normally represented in UTC time. 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).
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);
Learn more about the modern Date-Time API from Trail: Date Time.
Never use the 3-letter abbreviated timezone ID
Given below is an excerpt from the documentation page of TimeZone:
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.
I have some DateTime including TimeZone Europe/Vienna (+0200). It is fetched by this method:
settlementService.getPendingPeriodStart()
and look with toString like this:
2012-06-01T00:00:00.000+02:00
Now I want to save this date 2012-06-01 as java.util.Date, so I tried something like this:
transactionDate = settlementService.getPendingPeriodStart().withTime(0, 0, 0, 0).toDate();
But the result is this:
Thu May 31 22:00:00 UTC 2012
What's the best way to save the DateTime result as Date including the TimeZone offset, so transactionDate should be 2012-06-01. I could tinker with GregorianCalendar, but that's not what I like. This ought to be easier, isn't it?
By the way (if this isn't clear). The local system runs on UTC. That's why the result is Thu May 31 22:00:00 UTC 2012.
Unfortunately, the accepted answer is misguiding. As a matter of fact,
2012-06-01T00:00:00.000+02:00 = 2012-05-31T22:00:00Z
The Z on the right-hand side 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).
Writing 2012-06-01T00:00:00.000+02:00 as 2012-06-01, although a matter of just a function call, is dangerous for any business logic that depends on the timezone because it may have a different date in a timezone with a different offset value e.g. as shown above. 2012-06-01 is just a LocalDate which should be used to track events like birth date, wedding date etc.
java.time
The legacy date-time API (java.util date-time types and their formatting type, SimpleDateFormat etc.) is outdated and error-prone. It is recommended to stop using it completely and switch to java.time, the modern date-time API*.
Also, quoted below is a notice at the Home Page of Joda-Time:
Note that from Java SE 8 onwards, users are asked to migrate to java.time (JSR-310) - a core part of the JDK which replaces this project.
Solution using java.time, the modern API:
How to parse the given date-time string:
The given date-time string has a timezone offset and therefore it should be parsed to OffsetDateTime. Since 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.
OffsetDateTime odt = OffsetDateTime.parse("2012-06-01T00:00:00.000+02:00"); // 2012-06-01T00:00+02:00
How to get the date-time out of it in UTC:
There are multiple ways. The simplest way is to convert it into an Instant which represents an instantaneous point on the timeline which is in UTC.
Instant instant = odt.toInstant(); // 2012-05-31T22:00:00Z
Alternatively,
OffsetDateTime odtUtc = odt.withOffsetSameInstant(ZoneOffset.UTC); // 2012-05-31T22:00Z
How to get java.util.Date out of it:
If at all, you need an instance of java.util.Date from the instance of OffsetDateTime, you can use Date#from(Instant instant).
Date date = Date.from(instant); // Thu May 31 23:00:00 BST 2012 <--In my timezone
Note that a 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.
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSXXX", Locale.ENGLISH);
sdf.setTimeZone(TimeZone.getTimeZone("Etc/UTC"));
System.out.println(sdf.format(date)); // 2012-05-31T22:00:00.000Z
How to get the date part out of it:
As I have already explained, it is dangerous for any business logic that depends on the timezone. However, it's just a matter of a simple function call.
LocalDate localDate = odt.toLocalDate(); // 2012-06-01
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.
A date and the time zone of the user are 2 different things. One is a date, the other is a preference, or a presentation parameter.
Don't try to store them in the same field.
Consider that it wouldn't be even possible to store them together efficiently (without losing precision) as a date can be stored in a long only because it's specified that it's an UTC date.
You can save the time zone as an offset (a frequent recommendation is to keep the minutes in this offset ([hh]:[mm]) because of very small cases).
I think I found a solution. (If you know a better solution, just let me know)
DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
DateTime dateTimeWithTimeZone = new DateTime(DateTimeZone.forID("Europe/Vienna")).withDate(2012, 06, 01).withTime(0, 0, 0, 0);
Date dateWithTimeZoneIncluded = dateTimeWithTimeZone.toLocalDate().toDate();
System.out.println(dateFormat.format(dateWithTimeZoneIncluded));
The result is 2012-06-01 as expected.
I have the following date: 2011-08-12T20:17:46.384Z. What format is this? I'm trying to parse it with Java 1.4 via DateFormat.getDateInstance().parse(dateStr) and I'm getting
java.text.ParseException: Unparseable date: "2011-08-12T20:17:46.384Z"
I think I should be using SimpleDateFormat for parsing, but I have to know the format string first. All I have for that so far is yyyy-MM-dd, because I don't know what the T means in this string--something time zone-related? This date string is coming from the lcmis:downloadedOn tag shown on Files CMIS download history media type.
The T is just a literal to separate the date from the time, and the Z means "zero hour offset" also known as "Zulu time" (UTC). If your strings always have a "Z" you can use:
SimpleDateFormat format = new SimpleDateFormat(
"yyyy-MM-dd'T'HH:mm:ss.SSS'Z'", Locale.US);
format.setTimeZone(TimeZone.getTimeZone("UTC"));
Or using Joda Time, you can use ISODateTimeFormat.dateTime().
tl;dr
Standard ISO 8601 format is used by your input string.
Instant.parse ( "2011-08-12T20:17:46.384Z" )
ISO 8601
This format is defined by the sensible practical standard, ISO 8601.
The T separates the date portion from the time-of-day portion. The Z on the end means UTC (that is, an offset-from-UTC of zero hours-minutes-seconds). The Z is pronounced “Zulu”.
java.time
The old date-time classes bundled with the earliest versions of Java have proven to be poorly designed, confusing, and troublesome. Avoid them.
Instead, use the java.time framework built into Java 8 and later. The java.time classes supplant both the old date-time classes and the highly successful Joda-Time library.
The java.time classes use ISO 8601 by default when parsing/generating textual representations of date-time values.
The Instant class represents a moment on the timeline in UTC with a resolution of nanoseconds. That class can directly parse your input string without bothering to define a formatting pattern.
Instant instant = Instant.parse ( "2011-08-12T20:17:46.384Z" ) ;
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….
Not sure about the Java parsing, but that's ISO8601: http://en.wikipedia.org/wiki/ISO_8601
There are other ways to parse it rather than the first answer. To parse it:
(1) If you want to grab information about date and time, you can parse it to a ZonedDatetime(since Java 8) or Date(old) object:
// ZonedDateTime's default format requires a zone ID(like [Australia/Sydney]) in the end.
// Here, we provide a format which can parse the string correctly.
DateTimeFormatter dtf = DateTimeFormatter.ISO_DATE_TIME;
ZonedDateTime zdt = ZonedDateTime.parse("2011-08-12T20:17:46.384Z", dtf);
or
// 'T' is a literal.
// 'X' is ISO Zone Offset[like +01, -08]; For UTC, it is interpreted as 'Z'(Zero) literal.
String pattern = "yyyy-MM-dd'T'HH:mm:ss.SSSX";
// since no built-in format, we provides pattern directly.
DateFormat df = new SimpleDateFormat(pattern);
Date myDate = df.parse("2011-08-12T20:17:46.384Z");
(2) If you don't care the date and time and just want to treat the information as a moment in nanoseconds, then you can use Instant:
// The ISO format without zone ID is Instant's default.
// There is no need to pass any format.
Instant ins = Instant.parse("2011-08-12T20:17:46.384Z");
java.time
You do not need DateTimeFormatter to parse the given date-time string.
Java SE 8 Date-Time API(java.time API or 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 the 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).
The T in the string is just the Date-Time separator as per the 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) {
String strDateTime = "2011-08-12T20:17:46.384Z";
Instant instant = Instant.parse(strDateTime);
OffsetDateTime odt = OffsetDateTime.parse(strDateTime);
ZonedDateTime zdt = ZonedDateTime.parse(strDateTime);
System.out.println(instant);
System.out.println(odt);
System.out.println(zdt);
}
}
Output:
2011-08-12T20:17:46.384Z
2011-08-12T20:17:46.384Z
2011-08-12T20:17:46.384Z
Learn more about java.time, the modern Date-Time API* from Trail: Date Time.
The legacy Date-time API
The legacy Date-time API (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*.
For the sake of completeness, I've written a solution to parse this Date-Time string using the legacy API.
Do not use 'Z' in the pattern with the Date-Time parsing/formatting API.
As already described above, Z (without quotes) is the timezone designator for zero-timezone offset whereas 'Z' is just a character literal and it does not hold any meaning. Use the format, y-M-d'T'H:m:s.SSSXXX. Check the documentation to learn more about these symbols.
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Locale;
public class Main {
public static void main(String[] args) throws ParseException {
String strDateTime = "2011-08-12T20:17:46.384Z";
SimpleDateFormat sdf = new SimpleDateFormat("y-M-d'T'H:m:s.SSSXXX", Locale.ENGLISH);
Date date = sdf.parse(strDateTime);
// ...
}
}
Note that a 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). Since it does not hold any format and timezone information, it applies the format, EEE MMM dd HH:mm:ss z yyyy and the JVM's timezone to return the value of Date#toString derived from this milliseconds value. If you need to print the Date-Time in a different format and timezone, you will need to use a SimpleDateFormat with the desired format and the applicable timezone e.g.
sdf.setTimeZone(TimeZone.getTimeZone("Etc/UTC"));
String formatted = sdf.format(date);
System.out.println(formatted); // 2011-8-12T20:17:46.384Z
Joda Date-Time API
Quoted below is a notice at the Home Page of Joda-Time:
Note that from Java SE 8 onwards, users are asked to migrate to java.time (JSR-310) - a core part of the JDK which replaces this project.
Again, for the sake of completeness, I've written a solution to parse this Date-Time string using the Joda Date-Time API.
import org.joda.time.DateTime;
import org.joda.time.format.DateTimeFormat;
import org.joda.time.format.DateTimeFormatter;
public class Main {
public static void main(String[] args) {
String dateTimeStr = "2011-08-12T20:17:46.384Z";
DateTimeFormatter dtf = DateTimeFormat.forPattern("y-M-d'T'H:m:s.SSSZ").withOffsetParsed();
DateTime dateTime = dtf.parseDateTime(dateTimeStr);
System.out.println(dateTime);
}
}
Output:
2011-08-12T20:17:46.384Z
* 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.
If you guys are looking for a solution for Android, you can use the following code to get the epoch seconds from the timestamp string.
public static long timestampToEpochSeconds(String srcTimestamp) {
long epoch = 0;
try {
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O) {
Instant instant = Instant.parse(srcTimestamp);
epoch = instant.getEpochSecond();
} else {
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd'T'hh:mm:ss.SSSSSS'Z'", Locale.getDefault());
sdf.setTimeZone(TimeZone.getTimeZone("UTC"));
Date date = sdf.parse(srcTimestamp);
if (date != null) {
epoch = date.getTime() / 1000;
}
}
} catch (Exception e) {
e.printStackTrace();
}
return epoch;
}
Sample input: 2019-10-15T05:51:31.537979Z
Sample output: 1571128673
In JavaScript
let isoDateTimeString = new Date().toISOString();
Description
Date/time format like "YYYY-MM-DDThh:mm:ss.SSSZ" is ISO 8601 date/time format.
Z represent UTC time zone. With java8+, you can simply use Instant.
public static void main(String[] args) {
String time = "2022-06-08T04:55:01.000Z";
System.out.println(Instant.parse(time).toEpochMilli());
}
You can use the following example.
String date = "2011-08-12T20:17:46.384Z";
String inputPattern = "yyyy-MM-dd'T'HH:mm:ss.SSS'Z'";
String outputPattern = "yyyy-MM-dd HH:mm:ss";
LocalDateTime inputDate = null;
String outputDate = null;
DateTimeFormatter inputFormatter = DateTimeFormatter.ofPattern(inputPattern, Locale.ENGLISH);
DateTimeFormatter outputFormatter = DateTimeFormatter.ofPattern(outputPattern, Locale.ENGLISH);
inputDate = LocalDateTime.parse(date, inputFormatter);
outputDate = outputFormatter.format(inputDate);
System.out.println("inputDate: " + inputDate);
System.out.println("outputDate: " + outputDate);
This technique translates java.util.Date to UTC format (or any other) and back again.
Define a class like so:
import java.util.Date;
import org.joda.time.DateTime;
import org.joda.time.format.DateTimeFormat;
import org.joda.time.format.DateTimeFormatter;
public class UtcUtility {
public static DateTimeFormatter UTC = DateTimeFormat.forPattern("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'").withZoneUTC();
public static Date parse(DateTimeFormatter dateTimeFormatter, String date) {
return dateTimeFormatter.parseDateTime(date).toDate();
}
public static String format(DateTimeFormatter dateTimeFormatter, Date date) {
return format(dateTimeFormatter, date.getTime());
}
private static String format(DateTimeFormatter dateTimeFormatter, long timeInMillis) {
DateTime dateTime = new DateTime(timeInMillis);
String formattedString = dateTimeFormatter.print(dateTime);
return formattedString;
}
}
Then use it like this:
Date date = format(UTC, "2020-04-19T00:30:07.000Z")
or
String date = parse(UTC, new Date())
You can also define other date formats if you require (not just UTC)
#John-Skeet gave me the clue to fix my own issue around this. As a younger programmer this small issue is easy to miss and hard to diagnose. So Im sharing it in the hopes it will help someone.
My issue was that I wanted to parse the following string contraining a time stamp from a JSON I have no influence over and put it in more useful variables. But I kept getting errors.
So given the following (pay attention to the string parameter inside ofPattern();
String str = "20190927T182730.000Z"
LocalDateTime fin;
fin = LocalDateTime.parse( str, DateTimeFormatter.ofPattern("yyyyMMdd'T'HHmmss.SSSZ") );
Error:
Exception in thread "main" java.time.format.DateTimeParseException: Text
'20190927T182730.000Z' could not be parsed at index 19
The problem? The Z at the end of the Pattern needs to be wrapped in 'Z' just like the 'T' is. Change
"yyyyMMdd'T'HHmmss.SSSZ" to "yyyyMMdd'T'HHmmss.SSS'Z'" and it works.
Removing the Z from the pattern alltogether also led to errors.
Frankly, I'd expect a Java class to have anticipated this.