I have this String
Fri, 07 Aug 2020 18:00:00 +0000
And I need to convert it to a LocalDateTime
I tryed several ways:
create a DateTimeFormatter and parse the String
String dateString = "Fri, 07 Aug 2020 18:00:00 +0000";
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("E, dd MMM yyyy HH:mm:ss", Locale.getDefault());
LocalDateTime parsedDate = LocalDateTime.parse(publishedString, formatter);
Convert it to a Date with a SimpleDateFormat and then convert the resultDate to a LocalDateTime
String dateString = "Fri, 07 Aug 2020 18:00:00 +0000";
SimpleDateFormat dateFormatter = new SimpleDateFormat("E, dd MMM yyyy HH:mm:ss Z");
Date date = dateFormatter.parse(publishedString);
LocalDateTime localDateTime = date.toInstant().atZone(ZoneId.systemDefault()).toLocalDateTime();
both solution gives me the same exception:
java.time.format.DateTimeParseException: Text 'Fri, 07 Aug 2020 18:00:00 +0000' could not be parsed
at index 0 at java.base/java.time.format.DateTimeFormatter.parseResolved0(DateTimeFormatter.java:2046)
How can I convert that String?
I'd say use Locale.ROOT and don't forget the Z in the DateTimeFormatter class
String dateString = "Fri, 07 Aug 2020 18:00:00 +0000";
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("E, dd MMM yyyy HH:mm:ss Z", Locale.ROOT);
LocalDateTime parsedDate = LocalDateTime.parse(dateString, formatter);
tl;dr
OffsetDateTime.parse(
"Fri, 07 Aug 2020 18:00:00 +0000" ,
DateTimeFormatter.RFC_1123_DATE_TIME
)
See this code run live at IdeOne.com.
LocalDateTime is the wrong class
Your input string contains +0000 which indicates an offset-from-UTC.
So you should not be using LocalDateTime. That class purposely lacks any concept of time zone or offset. With LocalDateTime, your string Fri, 07 Aug 2020 18:00:00 +0000 will become 6M on August 7th 2020, but we won't know if that is 6 PM in Tokyo Japan, 6 PM in Toulouse France, or 6 PM in Toledo Ohio US — all different moments several hours apart.
OffsetDateTime
Instead, this value should be parsed as OffsetDateTime.
Parsing
Your input's format is that of RFC 1123. That particular format is predefined in java.time.
String input = "Fri, 07 Aug 2020 18:00:00 +0000";
DateTimeFormatter f = DateTimeFormatter.RFC_1123_DATE_TIME;
OffsetDateTime odt = OffsetDateTime.parse( input , f );
odt.toString(): 2020-08-07T18:00Z
I understand that you need a LocalDateTime for an API that due to a design problem beyond your control is trying to use LocalDateTime for a point in time.
If an external contract dictates in which time zone or at which UTC offset the LocalDateTime is to be understood, LocalDateTime can be made to work, at least for 99.977 % of cases. You will still have a programming error waiting to happen on the day when some colleague programmer does not read the contract, a problem that we cannot solve in the code, only try to mitigate through good commenting.
If for example the contract says UTC, then we need to make sure we convert the time to UTC. And we need the offset from the string for doing so.
ZoneOffset contractualOffset = ZoneOffset.UTC;
String stringWeveGot = "Fri, 07 Aug 2020 18:00:00 +0000";
LocalDateTime convertedDateTime = OffsetDateTime
.parse(stringWeveGot, DateTimeFormatter.RFC_1123_DATE_TIME)
.withOffsetSameInstant(contractualOffset)
.toLocalDateTime();
System.out.println(convertedDateTime);
Output:
2020-08-07T18:00
If the offset in the string is required to be 0 already, you need to validate that it is, or errors will go unnoticed and users will get wrong results. For example:
OffsetDateTime parsedOdt = OffsetDateTime
.parse(stringWeveGot, DateTimeFormatter.RFC_1123_DATE_TIME);
if (! parsedOdt.getOffset().equals(contractualOffset)) {
throw new IllegalStateException("Offset must be " + contractualOffset
+ ", was " + parsedOdt.getOffset());
}
LocalDateTime convertedDateTime = parsedOdt.toLocalDateTime();
If the contract mentions some time zone, convert to that time zone. I am taking Australia/Victoria as an example.
ZoneId contractualZone = ZoneId.of("Australia/Victoria");
String stringWeveGot = "Fri, 07 Aug 2020 18:00:00 +0000";
LocalDateTime convertedDateTime = OffsetDateTime
.parse(stringWeveGot, DateTimeFormatter.RFC_1123_DATE_TIME)
.atZoneSameInstant(contractualZone)
.toLocalDateTime();
System.out.println(convertedDateTime);
2020-08-08T04:00
You will get an ambiguous result at time anomalies where the clock is turned backward, for example at the fall back when summer time (DST) ends.
What went wrong in your code?
The cause of your exception is explained here:
new SimpleDateFormat(“hh:mm a”, Locale.getDefault()).parse(“04:30 PM”) giving Unparseable exception
java DateTimeFormatterBuilder fails on testtime
Related
How can I create an instance of java.util.Date out of a custom date time string?
This is what I tried so far:
Given I have the this custom date time string:
Fri Jul 29 12:56:35 UTC 2022
Using Joda-Time in the following piece of code:
String time = "Fri Jul 29 12:56:35 UTC 2022";
DateTimeFormatter df = DateTimeFormat.forPattern("EEE MMM dd HH:mm:ss z yyyy");
long millis = df.parseMillis(time);
I get the following exception:
java.lang.IllegalArgumentException: Invalid format: "Fri Jul 29 12:56:35 UTC 2022" is malformed at " UTC 2022"
at org.joda.time.format.DateTimeFormatter.parseMillis(DateTimeFormatter.java:644)
You can use a code like this :
String time = "Fri Jul 29 12:56:35 UTC 2022";
Date date = new Date(time);
long millis = date.getTime();
System.out.println(millis);
I have the following date string Tue Feb 04 2020 16:11:25 GMT+0200 (IST) where I'm trying to convert into date time using the following code:
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("EEE MMM d yyyy HH:mm:ss O (zzz)", Locale.ENGLISH);
LocalDate dateTime = LocalDate.parse("Tue Feb 04 2020 16:11:25 GMT+0200 (IST)", formatter);
And I got the following exception:
Text Tue Feb 04 2020 16:11:25 GMT+0200 (IST) could not be parsed at index 28
I look at the following SO question Java string to date conversion and I see that
O localized zone-offset offset-O GMT+8; GMT+08:00; UTC-08:00;
So why I got the exception?
The following pattern works.
"E MMM d u H:m:s 'GMT'Z (z)"
You can replace Z with x or X for the same result.
You can spell it out, if you want, but it is not necessary.
"EEE MMM dd uuuu HH:mm:ss 'GMT'ZZZ (zzz)"
You should parse that input to an OffsetDateTime, since the input string includes a Date, a Time, and an Offset.
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("E MMM d u H:m:s 'GMT'Z (z)", Locale.ENGLISH);
OffsetDateTime dateTime = OffsetDateTime.parse("Tue Feb 04 2020 16:11:25 GMT+0200 (IST)", formatter);
System.out.println(dateTime);
Output
2020-02-04T16:11:25+02:00
One of the reasons is that you are trying to parse a datetime String (date, time, zone and offset) to an object (LocalDate) that only stores year, month and day, nothing more.
Use a suitable class, say ZonedDateTime and adjust the parsing pattern a little:
you can't use the localized offset O because in a DateTimeFormatter it doesn't support the formatting your String has, which is GMT+0200 and the formatter supports GMT+8; GMT+08:00; UTC-08:00; only (mind the colon). Use a combination of an escaped GMT plus a regular offset symbol x
you have a single d but a representation of days that will always have two digits, so you need to use dd
you have to escape the brackets the zone abbreviation is enclosed in and I think a single z is sufficient for such an abbreviation
Considering all these aspects, you could parse the String as follows:
public static void main(String[] args) {
String parsePattern = "EEE MMM dd yyyy HH:mm:ss 'GMT'x '('z')'";
DateTimeFormatter formatter = DateTimeFormatter.ofPattern(parsePattern,
Locale.ENGLISH);
ZonedDateTime zdt = ZonedDateTime.parse("Tue Feb 04 2020 16:11:25 GMT+0200 (IST)", formatter);
System.out.println(zdt);
}
which then outputs (using the default formatter for ZonedDateTime)
2020-02-04T16:11:25+02:00[Asia/Jerusalem]
The problem here is the GMT+0200 if you use: GMT+02 it works.
But as already mentioned in the comments it is a little confusing that you use a variable called dateTime on something of the type LocalDate.
So your result will be only the date 2020-02-04 because LocalDate can only save this kind of data.
2 things - ZonedDateTime & missing ':' for 0
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("EEE MMM dd yyyy HH:mm:ss O (zzz)");
ZonedDateTime dateTime = ZonedDateTime.parse("Tue Feb 04 2020 16:11:25 GMT+02:00 (IST)", formatter);
This should work
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("EEE MMM d yyyy HH:mm:ss 'GMT'Z (z)", Locale.ENGLISH);
LocalDate dateTime = LocalDate.parse("Tue Feb 04 2020 16:11:25 GMT+0200 (IST)", formatter);
Do not use a fixed text for the timezone:
Do not use a fixed text (e.g. 'GMT') for the timezone as mentioned in the existing answers because that approach may fail for other locales.
The recommended solution:
import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Locale;
public class Main {
public static void main(String[] args) {
String strDateTime = "Tue Feb 04 2020 16:11:25 GMT+0200 (IST)";
DateTimeFormatter dtf = DateTimeFormatter.ofPattern("E MMM d u H:m:s VVZ (z)", Locale.ENGLISH);
ZonedDateTime zdt = ZonedDateTime.parse(strDateTime, dtf);
System.out.println(zdt);
}
}
Output:
2020-02-04T14:11:25Z[Atlantic/Reykjavik]
ONLINE DEMO
Learn more about the modern Date-Time API from Trail: Date Time.
you wrote one d and you passed 04 you should write dd instead of d like the following
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("EEE MMM dd yyyy HH:mm:ss O (zzz)", Locale.ENGLISH);
LocalDate dateTime = LocalDate.parse("Tue Feb 04 2020 16:11:25 GMT+0200 (IST)", formatter);
I've got a problem with the following date format: "Jan 15 2020 11:11:50.000 +0000". I need to parse the date into ms.
The odd behavior is that i can't use date.parse(). The function is always failing with "java.text.ParseException: Unparseable date: "Jan 15 2020 11:11:50.000 +0000";".
Someone got an idea how to manually parse the date or to change the date format within date.parse()?
Thanks all
With a ZonedDateTime and this pattern LLL d yyyy HH:mm:ss.SSS Z (DateTimeFormatter) you'll be able to handle it
String value = "Jan 15 2020 11:11:50.000 +0000";
DateTimeFormatter dt = DateTimeFormatter.ofPattern("LLL d yyyy HH:mm:ss.SSS Z", Locale.ENGLISH);
ZonedDateTime l = ZonedDateTime.parse(value, dt);
System.out.println(l.format(dt)); // Jan 15 2020 11:11:50.000 +0000
I have a MapperUtility class that needs to map a string from a web service that sends a string time "Fri Nov 22 2013 12:12:13 GMT+0000 (UTC)"
Now, I am converting it to LocalDateTime with this code:
String time = "Fri Nov 22 2013 12:12:13 GMT+0000 (UTC)";
DateTimeFormatter dtf = DateTimeFormatter.ofPattern("E MMM dd yyyy HH:mm:ssZ");
dtf.withZone(ZoneId.of("UTC"));
LocalDateTime convertedDate = LocalDateTime.parse(time, dtf);
But I am having an exception starting the GMT+0000 (UTC).
It works when I removed the characters beyond the GMT.
After converting them to Date Time, I need to convert them to long milliseconds.
Please advise. Thanks.
You may build such pattern using DateTimeFormatterBuilder:
static final DateTimeFormatter DF = new DateTimeFormatterBuilder()
.append(DateTimeFormatter.ofPattern("E MMM dd yyyy HH:mm:ss"))
.appendLiteral(" GMT")
.appendOffset("+HHmm", "+0000")
.optionalStart()
.appendLiteral(" (")
.appendZoneId()
.appendLiteral(')')
.optionalEnd()
.toFormatter()
.withLocale(Locale.US);
Then, just:
String date = "Fri Nov 22 2013 12:12:13 GMT+0000 (UTC)";
long ms = OffsetDateTime.parse(date, DF).toInstant().toEpochMilli(); // 1385122333000
An inefficient way to make the parser accept your string verbatim is:
String[] timezones = {"UTC", "BST", "CET", "PST", ...};
StringBuilder sb = new StringBuilder(timezones.length * 8 + 38);
sb.append("E MMM dd yyyy HH:mm:ss' GMT'Z' ('");
for(String timezone : timezones)
sb.append("['").append(timezone).append("']");
sb.append("')'");
DateTimeFormatter dtf = DateTimeFormatter.ofPattern(sb.toString());
String time = "Fri Nov 22 2013 12:12:13 GMT+0000 (UTC)";
ZonedDateTime convertedDate = ZonedDateTime.parse(time, dtf);
System.out.println(convertedDate);
I changed to ZonedDateTime too because otherwise it discards the timezone and always returns 12:12:13 regardless of what's after the GMT+.
But it gets unwieldy pretty quick because of the inexhaustible list of possible time zone abbreviations.
A better way is to preprocess the string:
String time = "Fri Nov 22 2013 12:12:13 GMT+0000 (UTC)";
String preprocessed = time.replaceAll("(.*) GMT([+-][0-9]{4}).*", "$1$2");
System.out.println(preprocessed);
DateTimeFormatter dtf = DateTimeFormatter.ofPattern("E MMM dd yyyy HH:mm:ssZ");
ZonedDateTime convertedDate = ZonedDateTime.parse(preprocessed, dtf);
System.out.println(convertedDate);
Then the conversion to milliseconds is a bit tricky to find in the extensive java.time API but eventually it turns out to be as simple as:
convertedDate.toInstant().toEpochMilli()
String time = "Fri Nov 22 2013 12:12:13 GMT+0000 (UTC)";
DateTimeFormatter dtf = DateTimeFormatter.ofPattern("E MMM dd yyyy HH:mm:ss 'GMT'xx (zzz)", Locale.ENGLISH);
ZonedDateTime zdt = ZonedDateTime.parse(time, dtf);
OffsetDateTime odt = OffsetDateTime.parse(time, dtf);
boolean offsetAgrees = zdt.getOffset().equals(odt.getOffset());
if (offsetAgrees) {
long millisecondsSinceEpoch = odt.toInstant().toEpochMilli();
System.out.println("Milliseoncds: " + millisecondsSinceEpoch);
} else {
System.out.println("Offset " + odt.getOffset() + " does not agree with time zone " + zdt.getZone());
}
Output:
Milliseoncds: 1385122333000
I am parsing GMT as a literal, +0000 as an offset and UTC as a time zone abbreviation. For the offset we could have used xx or ZZZ. Since Fri and Nov are in English, we need to specify an English speaking locale.
I have added a little complication compared to your code because we want to validate that the offset and the time zone agree. OffsetDateTime.parse uses the offest (+0000) directly whereas ZonedDateTime.parse derives the offset from the time zone ( UTC). My check is very bare-bones and may be extended to accept two possible offsets in the transition from summer time (DST) and multiple time zones sharing the same abbreviation.
PS Don’t use LocalDateTime. This type can neither hold an offset nor time zone, so you can no longer attach your date and time to a specific point on the time line, which you need to do to obtain milliseconds since the epoch.
I tried the below approach and searched in Web to find the solution for this but no luck : looking for the solution for converting a String in IST to PST:
String string = new Date().toString();
System.out.println(string);
SimpleDateFormat dt = new SimpleDateFormat("EEE MMM dd HH:mm:ss zzz yyyy");
dt.setTimeZone(TimeZone.getTimeZone("PST"));
Date D = dt.parse(string);
System.out.println(""+ D);
Even when I set time zone as PST, I am seeing out put in IST
here is the out put:
Tue Apr 18 18:58:09 IST 2017
Tue Apr 18 18:58:09 IST 2017
I tried another Option here I am seeing even it is showing the time in PST but I see below output it is a bit confusing:
public static Date convertFromOneTimeZoneToOhter(Date dt,String from,String to ) {
TimeZone fromTimezone =TimeZone.getTimeZone(from);//get Timezone object
TimeZone toTimezone=TimeZone.getTimeZone(to);
long fromOffset = fromTimezone.getOffset(dt.getTime());//get offset
long toOffset = toTimezone.getOffset(dt.getTime());
//calculate offset difference and calculate the actual time
long convertedTime = dt.getTime() - (fromOffset - toOffset);
Date d2 = new Date(convertedTime);
return d2;
}
OUT PUT:
Converted Date : Tue Apr 18 06:28:09 IST 2017
Can someone please help on this: I found lot of solutions on converting IST Date time to PST String but not IST/EST Date to PST Date.
As I mentioned above we can format to a String, but I am looking for an example of converting back to Date
You should look into Java 8's new Date API that handles timezones directly
// Get the current date and time
ZonedDateTime date1 = ZonedDateTime.parse("2007-12-03T10:15:30+05:30[Asia/Karachi]");
System.out.println("date1: " + date1);
ZonedDateTime zonedDateTime = ZonedDateTime.now();
System.out.println("Zoned Date Time: " + zonedDateTime);
ZoneId id = ZoneId.of("Europe/Paris");
System.out.println("ZoneId: " + id);
ZoneId currentZone = ZoneId.systemDefault();
System.out.println("CurrentZone: " + currentZone);
Prints :
date1: 2007-12-03T10:15:30+05:00[Asia/Karachi]
Zoned Date Time: 2017-04-18T09:52:09.045-04:00[America/New_York]
ZoneId: Europe/Paris
CurrentZone: America/New_York
Since some readers here will use Java 8 or later and some Java 7 or earlier, I will treat both.
I recommend you use the java.time classes introduced in Java 8 if you can:
ZoneId targetTz = ZoneId.of("America/Los_Angeles");
String string = "Tue Apr 18 18:58:09 +0300 2017";
DateTimeFormatter format = DateTimeFormatter.ofPattern("EEE MMM dd HH:mm:ss ZZZ uuuu",
Locale.ENGLISH);
ZonedDateTime sourceTime = ZonedDateTime.parse(string, format);
ZonedDateTime targetTime = sourceTime.withZoneSameInstant(targetTz);
String result = targetTime.format(format);
System.out.println(result);
This prints:
Tue Apr 18 08:58:09 -0700 2017
You said you wanted a PST date, and this is exactly what the ZonedDateTime gives you: date and time with time zone information.
In the example I am giving a zone offset, +0300 (corresponding to Israel Daylight Time) in the string. I understood that it wasn’t important to you how the time zone was given. I want to avoid the three and four letter time zone abbreviations like IST. Not only may IST mean either Irish Standard Time, Israel Standard Time or India Standard Time. I furthermore noticed that the java.time classes pick up 18:58:09 IST as 18:58:09 IDT (UTC+3) because it knows Israel is on DST on April 18; the SimpleDateFormat that I return to below takes IST more literally and interprets 18:58:09 IST as 18:58:09 +0200, which is 1 hour later in UTC.
You can use the java.time classes with Java 1.7 if you want. You can get them in the ThreeTen Backport.
If you don’t want to use java.time, the way to do it with the outdated classes from Java 1.0 and 1.1 is not that different in this case, only I cannot give you the PST date you asked for:
TimeZone targetTz = TimeZone.getTimeZone("America/Los_Angeles");
String string = "Tue Apr 18 18:58:09 +0300 2017";
SimpleDateFormat dt = new SimpleDateFormat("EEE MMM dd HH:mm:ss ZZZ yyyy", Locale.ENGLISH);
Date d = dt.parse(string);
dt.setTimeZone(targetTz);
String result = dt.format(d);
System.out.println(result);
It prints the same result as above. However, you notice there is only one Date object. A Date object cannot hold any time zone information, so if you need this, you will have to bring the targetTz object along with d. It’s a common misunderstanding that there’s supposed to be a time zone in the Date object, probably greatly helped by the fact that its toString() prints a time zone. This is always the JVM’s default time zone and doesn’t come from the Date object, though.