I am trying to parse following datetime String to LocalDateTimeObject, however I am not able to identify the format of the datetime string.
Sat, 09 Oct 2021 02:10:23 -0400
String s = "Sat, 09 Oct 2021 02:10:23 -0400";
DateTimeFormatter formatter = DateTimeFormatter.ISO_OFFSET_DATE_TIME;
LocalDateTime dateTime = LocalDateTime.parse(s, formatter);
System.out.println(dateTime);
How should I determine the pattern of the above string?
You should first check if the date string matches any of the Predefined Formatters.
If not, then you have to make your own Formatter using .ofPattern(String pattern) or .ofPattern(String pattern, Locale locale). To do this, you can see all the defined pattern letters here in section Patterns for Formatting and Parsing.
For your example, you can use either DateTimeFormatter.RFC_1123_DATE_TIME:
DateTimeFormatter formatter = DateTimeFormatter.RFC_1123_DATE_TIME;
OffsetDateTime dateTime = OffsetDateTime.parse(s, formatted);
or:
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("EEE, dd MMM yyyy HH:mm:ss Z");
OffsetDateTime dateTime = OffsetDateTime.parse(s, formatted);
Note that OffsetDateTime is used to represent the date-time with an offset from UTC.
Symbol Meaning
------ -------
E day-of-week
d day-of-month
M month-of-year
y year-of-era
H hour-of-day (0-23)
m minute-of-hour
s second-of-minute
Z zone-offset
Related
How to convert date format "2021-02-28 13:38:00.597+0000" to "Mon, Feb 28,2021 15:25:00 UTC" UTC format in Scala?
If you are using an older Java version prior to Java 8, it's best to use the DateTimeFormat from joda-time. BTW, the +0000 zone offset is for UTC, so I could have omitted withZoneUTC(), but I still used it for the first date just to be safe:
val oldDateString = "2021-02-28 13:38:00.597+0000"
val OldFormat = "yyyy-MM-dd HH:mm:ss.SSSZ"
val NewFormat = "EEE, MMM dd, yyyy HH:mm:ss z"
val formatterOld = DateTimeFormat.forPattern(OldFormat)
val formatterNew = DateTimeFormat.forPattern(NewFormat)
val dt = formatterOld.withZoneUTC().parseDateTime(oldDateString)
val dateStringInUTC = formatterNew.withZoneUTC().print(dt)
println(dt) // 2021-02-28T13:38:00.597Z
println(dateStringInUTC) // Sun, Feb 28, 2021 13:38:00 UTC
UPDATE: For Java 8 and newer, the java.time API is your friend. Similarly, withZoneSameInstant(ZoneOffset.UTC) was not really needed:
val oldDateString = "2021-02-28 13:38:00.597+0000"
val OldFormat = "yyyy-MM-dd HH:mm:ss.SSSZZZ"
val NewFormat = "EEE, MMM dd, yyyy HH:mm:ss z"
val formatterOld = DateTimeFormatter.ofPattern(OldFormat)
val formatterNew = DateTimeFormatter.ofPattern(NewFormat)
val zdt = ZonedDateTime.parse(oldDateString, formatterOld)
val dateStringInUTC = zdt.withZoneSameInstant(ZoneId.of("UTC")).format(formatterNew)
println(zdt) // 2021-02-28T13:38:00.597Z
println(dateStringInUTC) // Sun, Feb 28, 2021 13:38:00 UTC
UPDATE: Switched to using ZoneId.of("UTC") instead of ZoneOffset.UTC because the latter does not get the String UTC printed at the end, even though ZoneOffset extends ZoneId, as #deHaar mentioned.
If you could use java.time, you would need
a DateTimeFormatter for parsing Strings with the format of your input example, which is quite near to ISO standard, but is missing the 'T' between date and time of day
another DateTimeFormatter for outputting the temporal content in the desired format, which includes (English) abbreviations for day of week and month of year
an OffsetDateTime for parsing the String with the first DateTimeFormatter and
a ZonedDateTime for the temporal value in UTC
This is how I would do it in Java:
public static void main(String[] args) {
// example String
String utcDatetimeString = "2021-02-28 13:38:00.597+0000";
// prepare a formatter that can parse a String of this format
DateTimeFormatter dtfIn = DateTimeFormatter.ofPattern(
"uuuu-MM-dd HH:mm:ss.SSSxxxx",
Locale.ENGLISH
);
// parse it to an OffsetDateTime
OffsetDateTime odt = OffsetDateTime.parse(utcDatetimeString, dtfIn);
// then convert it to a ZonedDateTime applying UTC zone
ZonedDateTime zdt = odt.atZoneSameInstant(ZoneId.of("UTC"));
// prepare a formatter that produces the desired output
DateTimeFormatter dtfOut = DateTimeFormatter.ofPattern(
"EEE, MMM dd, uuuu HH:mm:ss zzz",
Locale.ENGLISH
);
// and print the ZonedDateTime using the formatter
System.out.println(zdt.format(dtfOut));
}
Output:
Sun, Feb 28, 2021 13:38:00 UTC
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 have date of type "EEE MM DD HH:mm:ss zzz yyyy" (Wed Mar 04 03:34:45 GMT+08:00 2020) and "yyyy-MM-dd hh:mm:ss" (2020-02-04 02:10:58).How to compare this two date in java?
Both dates are in same timezone.
If you assume that the timezone of the second date is the same as for the first one then you can just use java.time. It has all parsing tools you need. Any other fixed timezone works as well.
Here is an example:
String a = "Wed Mar 04 03:34:45 GMT+08:00 2020";
String b = "2020-02-04 02:10:58";
ZonedDateTime parsedA;
ZonedDateTime parsedB;
DateTimeFormatter formatterA = DateTimeFormatter.ofPattern("EEE MMM dd HH:mm:ss zzz yyyy");
parsedA = ZonedDateTime.parse(a, formatterA);
DateTimeFormatter formatterB = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
parsedB = LocalDateTime.parse(b, formatterB).atZone(parsedA.getZone());
// What do you want to compare? For example you can tell if a is after b.
System.out.println(parsedA.isAfter(parsedB));
Have a look here if you need another format and need a listing of Pattern Letters and Symbols.
First of all these two dates are not comparable because of missing timezone in the second date.
Secondly, If you still want to do that with system's default time zone then you need to bring both the dates into common format.
Parse the dates into Date object and then you can play around it:
DateFormat dateFormat1 = new SimpleDateFormat("EEE MMM dd HH:mm:ss Z yyyy");
Date date1 = dateFormat1.parse("Wed Mar 04 03:34:45 GMT+08:00 2020");
DateFormat dateFormat2 = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");
Date date2 = dateFormat2.parse("2020-02-04 02:10:58");
System.out.println(date1.after(date2));
There is a difference between time zone and time zone offset. The Date-Time string Wed Mar 04 03:34:45 GMT+08:00 2020 has a time zone offset, not a time zone. A time zone is unique and therefore it has an ID e.g. ZoneId.of("America/New_York") whereas a time zone offset tells you about the amount of time by which a given time is offset from the UTC time. There can be many time zones falling on the same time zone offset. Check List of tz database time zones to learn more about it. So, the most appropriate type to parse Wed Mar 04 03:34:45 GMT+08:00 2020 into is OffsetDateTime.
Since the second Date-Time string 2020-02-04 02:10:58 has neither a time zone nor a time zone offset, parse it into LocalDateTime.
Make sure to use Locale with the formatter because Date-Time parsing/formatting API is Locale-sensitive.
As long as the second Date-Time string refers to a Date-Time at the same timezone offset (i.e. GMT+08:00), you can do either of the two to compare them
Convert the first Date-Time string into LocalDateTime after parsing and then compare it with the second Date-Time string parsed into a LocalDateTime.
Convert the second Date-Time string into an OffsetDateTime after parsing and then compare it with the first Date-Time string parsed into an OffsetDateTime.
I would prefer the first approach as it is simpler. However, for the sake of completeness, I've shown below both approaches.
First approach:
DateTimeFormatter odtFormatter = DateTimeFormatter.ofPattern("EEE MMM dd HH:mm:ss O uuuu", Locale.ENGLISH);
OffsetDateTime firstOffsetDateTime = OffsetDateTime.parse("Wed Mar 04 03:34:45 GMT+08:00 2020", odtFormatter);
LocalDateTime firstLocalDateTime = firstOffsetDateTime.toLocalDateTime();
DateTimeFormatter ldtFormatter = DateTimeFormatter.ofPattern("uuuu-MM-dd HH:mm:ss", Locale.ENGLISH);
LocalDateTime secondLocalDateTime = LocalDateTime.parse("2020-02-04 02:10:58", ldtFormatter);
// Compare the two LocalDateTime values using isBefore, isAfter, equals etc.
if (firstLocalDateTime.isBefore(secondLocalDateTime)) {
// ...
}
Second approach:
DateTimeFormatter odtFormatter = DateTimeFormatter.ofPattern("EEE MMM dd HH:mm:ss O uuuu", Locale.ENGLISH);
OffsetDateTime firstOffsetDateTime = OffsetDateTime.parse("Wed Mar 04 03:34:45 GMT+08:00 2020", odtFormatter);
DateTimeFormatter ldtFormatter = DateTimeFormatter.ofPattern("uuuu-MM-dd HH:mm:ss", Locale.ENGLISH);
LocalDateTime secondLocalDateTime = LocalDateTime.parse("2020-02-04 02:10:58", ldtFormatter);
OffsetDateTime secondOffsetDateTime = secondLocalDateTime.atOffset(firstOffsetDateTime.getOffset());
// Compare the two OffsetDateTime values using isBefore, isAfter, equals etc.
if (firstOffsetDateTime.isBefore(secondOffsetDateTime)) {
// ...
}
I also prefer u to y with a DateTimeFormatter.
Learn more about the the modern date-time API from Trail: Date Time.
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'm trying convert a String to Date, but I haven't gotten it.
My String is in the format:
"Fri Jun 13 10:24:01 BRT 2014"
I have Googled and found this resolution, but still continue catching an Exception.
Here is my code:
java.text.SimpleDateFormat df = new java.text.SimpleDateFormat("EEE MMM dd HH:mm:ss 'BRT' yyyy", Locale.getDefault());
df.setTimeZone(TimeZone.getTimeZone("BRT"));
try {
return df.parse(dateString);
} catch (Exception e) {
return null;
}
You need:
SimpleDateFormat df = new SimpleDateFormat("EEE MMM dd HH:mm:ss z yyyy", Locale.ENGLISH);
df.setTimeZone(TimeZone.getTimeZone("BRT"));
DateFormat utcFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssZ");
Date d = df.parse("Fri Jun 13 10:24:01 BRT 2014");
System.out.println(utcFormat.format(d)); // output: 2014-06-13T12:24:01+0200
Consider following corrections:
Locale.ENGLISH instead of Locale.getDefault() enables reliable parsing of english names like "Jun" or "Fri"
Use pattern symbol z instead of literal 'BRT' because else the parser cannot interprete the string "BRT" as an abbreviation of a timezone name that is interpreting as Brazil Standard Time (in your case just parsing as literal hence not taking in account the timezone offset of UTC-03:00).
The answer by Meno Hochschild is correct. Pay attention to those items (1) & (2).
Joda-Time
FYI, using Joda-Time or java.time (new package in Java 8) is recommended over the notoriously troublesome java.util.Date and .Calendar classes.
Example in Joda-Time 2.3.
String input = "Fri Jun 13 10:24:01 BRT 2014";
Via a Locale object, specify the language by which to interpret the day-of-week and month names during the parsing.
DateTimeFormatter formatter = DateTimeFormat.forPattern( "EEE MMM dd HH:mm:ss z yyyy" ).withLocale( Locale.ENGLISH );
Rather than rely on the default, specify a time zone to assign to the fresh DateTime object resulting from the parsing. Unlike a java.util.Date object, a DateTime truly knows its own assigned time zone.
DateTimeZone timeZone = DateTimeZone.forID( "America/Sao_Paulo" ); // Arbitrary choice of example time zone.
DateTime dateTime = formatter.withZone( timeZone ).parseDateTime( input );
Usually you should be working in Universal Time (UTC). Easy to convert.
DateTime dateTimeUtc = dateTime.withZone( DateTimeZone.UTC );
Built-in formatter is based on ISO 8601 format.
String output = dateTime.toString();
Or define your own pattern, or use one of the other pre-defined formats.
String outputInAwkwardFormat = formatter.print( dateTime );