I am struggling with Java 8 DateTimeFormatter.
I would like to convert a given String to dateFormat and parse to LocalDateTime
Here is my code
DateTimeFormatter f = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss")
String text = "2020-01-01T01:01:11.123Z"
LocalDateTime date = LocalDateTime.parse(text, f)
But Java throws
Text could not be parsed, unparsed text found at index 19
If I change ofPattern to yyyy-MM-dd'T'HH:mm:ss.SSSX, my code executes without any error.
But I don’t want to use millisecond and time zone.
Do this instead:
String text = "2020-01-01T01:01:11.123Z";
LocalDateTime date = ZonedDateTime.parse(text)
.toLocalDateTime();
To get rid of the milliseconds information, do:
LocalDateTime date = ZonedDateTime.parse(text)
.truncatedTo(ChronoUnit.SECONDS)
.toLocalDateTime();
You can also use OffsetDateTime in place of ZonedDateTime.
Related
I have a problem parsing a String to LocalDate.
According to similar questions on Stackoverflow and documentation I am using the correct values dd (day of the month), MM (month of the year) and yyyy (year).
My String
String mydate = "18.10.2022 07:50:18";
My parsing test code
System.out.println(
LocalDate.parse(testPasswordExp)
.format(DateTimeFormatter.ofPattern("dd.MM.yyyy HH:mm:ss")
)
);
Error:
Caused by: java.lang.RuntimeException:
java.time.format.DateTimeParseException:
Text '18.10.2022 07:50:18' could not be parsed at index 0
The main problem of your code example is that you first parse the String to a LocalDate without the use of a suitable DateTimeFormatter and then format() it with a DateTimeFormatter that tries to format hour of day, minute of hour and second of minute which just aren't there in a LocalDate.
You can parse this String to a LocalDate directly, but better parse it to a LocalDateTime because your String contains more than just information about
day of month
month of year
year
Your myDate (and probably the testPasswordExp, too) has a time of day. You can get a LocalDate as the final result that way, too, because a LocalDateTime can be narrowed down toLocalDate().
A possible way:
public static void main(String[] args) {
// example datetime
String testPasswordExp = "18.10.2022 07:50:18";
System.out.println(
LocalDateTime // use a LocalDateTime and…
.parse( // … parse …
testPasswordExp, // … the datetime using a specific formatter,
DateTimeFormatter.ofPattern("dd.MM.uuuu HH:mm:ss")
).toLocalDate() // then extract the LocalDate
);
}
Output:
2022-10-18
You don't use the specified format for parsing, you use it to format the parsed date.
LocalDate.parse(mydate)
… uses the default ISO_LOCAL_DATE format. You are looking for this overload:
LocalDate.parse(mydate, DateTimeFormatter.ofPattern("dd.MM.yyyy HH:mm:ss"))
This method uses the specified format for parsing string to date. See this code run at Ideone.com.
Note that you are using LocalDate, meaning it will throw away the time part, keeping only the date after parsing. You probably meant to use LocalDateTime.
You can use
String mydate = "18.10.2022 07:50:18";
LocalDate ld = LocalDate.parse(mydate, DateTimeFormatter.ofPattern("dd.MM.yyyy HH:mm:ss"));
System.out.println(ld.toString());
I need to get the datetime of 1 year back considering the current datetime. The format needed to be in "yyyy-MM-dd HH:mm:ss.SSS"
ex : 2019-08-13 12:00:14.326
I tried following. But getting an error.
LocalDate now = LocalDate.now();
LocalDate localDate = LocalDate.parse(now.toString(), DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss.SSS")).minusYears(1);
Below Exception returned:
DateTimeParseException: Text '2020-08-13' could not be parsed
What's the best way to do this in Java 8+ ?
A LocalDate does not hold any information about hours, minutes, seconds or any unit below, instead, it holds information about year, month and day. By calling LocalDate.now() you are getting the date of today (the day of code execution).
If you need the time as well, use a LocalDateTime, which has a method now(), too, and actually consists of a LocalDate and a LocalTime.
Your error message tells you that the content of a LocalDate cannot be formatted using the given pattern (-String) "yyyy-MM-dd HH:mm:ss.SSS" because that pattern requires values for hours (HH), minutes (mm), seconds (ss) and milliseconds (SSS are fraction of seconds and three of them make it be milliseconds).
For parsing Strings or formatting datetimes, a LocalDateTime may be suitable but if you want to reliably add or subtract a year or any other amount of time, you'd rather use a class that considers time zones, offsets and daylight saving like ZonedDateTime or OffsetDateTime...
The LocalDate is the wrong class for your requirement as it does not hold the time information. You can use LocalDateTime but I suggest you use OffsetDateTime or ZonedDateTime so that you can get the flexibility of using the Zone Offset and Zone ID. Check https://docs.oracle.com/javase/tutorial/datetime/iso/overview.html for an overview of date-time classes.
Also, keep in mind that a date or time or date-time object is an object that just holds the information about date/time; it doesn't hold any information about formatting and therefore no matter what you do when you print their objects, you will always get the output what their toString() methods return. In order to format these classes or in other words, to get a string representing a custom format of these objects, you have formatting API (e.g. the modern DateTimeFormatter or legacy SimpleDateFormat) at your disposal.
A sample code:
import java.time.OffsetDateTime;
import java.time.ZoneOffset;
import java.time.format.DateTimeFormatter;
public class Main {
public static void main(String[] args) {
// Get the current date & time at UTC
OffsetDateTime odtNow = OffsetDateTime.now(ZoneOffset.UTC);
System.out.println("Now at UTC: " + odtNow);
// Get the date & time one year ago from now at UTC
OffsetDateTime odtOneYearAgo = odtNow.minusYears(1);
System.out.println("One year ago at UTC: " + odtNow);
// Define a formatter for the output in the desired pattern
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss.SSS");
// Format the date & time using your defined formatter
String formattedDateTimeOneYearAgo = formatter.format(odtOneYearAgo);
System.out.println("Date Time in the pattern, yyyy-MM-dd HH:mm:ss.SSS: " + formattedDateTimeOneYearAgo);
}
}
Output:
Now at UTC: 2020-08-13T08:50:36.277895Z
One year ago at UTC: 2020-08-13T08:50:36.277895Z
Date Time in the pattern, yyyy-MM-dd HH:mm:ss.SSS: 2019-08-13 08:50:36.277
May not be the best way, but this will do it
LocalDateTime date = LocalDateTime.now().minusYears(1);
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss.SSS");
System.out.println(date.format(formatter));
You say you want date+time from 1 year back, but you give it only a date (LocalDate). If you just want the date, all you need to do is:
LocalDate now = LocalDate.now();
LocalDate then = now.minusYears(1);
And if you want the timestamp also, then:
LocalDateTime now = LocalDateTime.now();
LocalDateTime then = now.minusYears(1);
And so on for other objects.
As mentioned you should use LocalDateTime instead of LocalDate.
Your exception was thrown because your input String is in ISO_DATE_TIME format
Java Doc
DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss.SSS");
String now = dateTimeFormatter.format(LocalDateTime.now());
LocalDateTime localDate = LocalDateTime.parse(now, dateTimeFormatter);
In my spring boot application I have to convert ISO 8601 datetime to localdatetime without using JODA. Currently what I am doing is
String receivedDateTime = "2019-11-13T00:11:08+05:00";
ZonedDateTime zonedDateTime = ZonedDateTime.parse(receivedDateTime);
DateFormat utcFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'");
utcFormat.setTimeZone(TimeZone.getTimeZone("UTC"));
Date date = new Date();
try {
date = utcFormat.parse(zonedDateTime.toString());
} catch (ParseException e) {
e.printStackTrace();
}
When I am using receivedDateTime with +00:00 like "2019-11-13T00:11:08+00:00" then it does not give any parsing error but not converting either. When I use +01:00 at the end then it also gives the parsing error.
UPDATE: 1
As per #Deadpool answer, I am using it like
String receivedDateTime = "2019-11-13T00:11:08+05:00";
DateTimeFormatter formatter = new DateTimeFormatterBuilder()
.append(DateTimeFormatter.ISO_LOCAL_DATE_TIME)
.optionalStart().appendOffset("+HH:MM", "+00:00").optionalEnd()
.optionalStart().appendOffset("+HHMM", "0000").optionalEnd()
.toFormatter();
OffsetDateTime dt = OffsetDateTime.parse(receivedDateTime, formatter);
LocalDateTime ldt = dt.toLocalDateTime();
System.out.println(ldt);
and the the value of ldt it print is 2019-11-13T00:11:08.
UPDATE 2:
I tried using C# the same example and it gives me this date time {2019-11-12 11:11:08 AM}, which looks correct as the input time GMT +5 Hours and local time is EST America. So, when it converted it then it went back to 12th of Nov. Here is the code
var timeString = "2019-11-13T00:11:08+05:00";
DateTime d2 = DateTime.Parse(timeString, null, System.Globalization.DateTimeStyles.RoundtripKind);
Console.WriteLine("Hello World!" + d2);
UPDATE 3: So it boils down to following solution input String "2019-11-13T06:01:41+00:00" and output is local date "2019-11-13T00:01:41" Where system defauld ZoneId is "America/Chicago" which is -06:00 GMT
private LocalDateTime convertUtcStringToLocalDateTime(String UtcDateTime) {
DateTimeFormatter formatter = new DateTimeFormatterBuilder()
.append(DateTimeFormatter.ISO_LOCAL_DATE_TIME)
.optionalStart().appendOffset("+HH:MM", "+00:00").optionalEnd()
.optionalStart().appendOffset("+HHMM", "0000").optionalEnd()
.toFormatter();
OffsetDateTime dateTime = OffsetDateTime.parse(UtcDateTime, formatter);
return dateTime.atZoneSameInstant(ZoneId.of(ZoneId.systemDefault().getId())).toLocalDateTime();
}
Using java.time alone this is simpler than you seem to think:
String receivedDateTime = "2019-11-13T00:11:08+05:00";
OffsetDateTime parsedDateTime = OffsetDateTime.parse(receivedDateTime);
ZonedDateTime dateTimeInMyTimeZone
= parsedDateTime.atZoneSameInstant(ZoneId.systemDefault());
System.out.println(dateTimeInMyTimeZone);
When I ran this in America/Toronto time zone, the output was:
2019-11-12T14:11:08-05:00[America/Toronto]
Since your string contains an offset, +05:00, and no time zone, like Asia/Karachi, use an OffsetDateTime for parsing it. Then convert to your local time zone using the atZoneSameInstant method. Even though you asked for your local time, don’t be fooled into using LocalDateTime. That class represent a date and time without any time zone, which is not what you need (and seldom needed at all).
Fortunately it’s easy to avoid the old classes SimpleDateFormat, DateFormat, TimeZone and Date. They were always poorly designed, the first two in particular are notoriously troublesome. They are all long outdated now. Instead get all the functionality we dream of from java.time, the modern Java date and time API.
What happened in your code?
Don’t use 'Z' in a format pattern string (and I repeat, don’t use SimpleDateFormat).
No matter if you use ZonedDateTime or OffsetDateTime, when you use toString with offset zero (as parsed from +00:00), the offset is printed as Z, which matches the 'Z' in your format pattern string, so your second parsing works. Only parsing once, converting back to string and parsing again is needlessly complicated. Worse when the original offset was +01:00 or +05:00. These are rendered the same again from toString, so don’t match 'Z', which caused your ParseException. Never use 'Z' in a format pattern string. Z denotes an offset of zero and needs to be parsed as an offset for you to get the correct result.
By using DateTimeFormatter you can customize the date format with different offset format by making them optional
DateTimeFormatter formatter = new DateTimeFormatterBuilder()
.append(DateTimeFormatter.ISO_LOCAL_DATE_TIME)
.optionalStart().appendOffset("+HH:MM", "+00:00").optionalEnd()
.optionalStart().appendOffset("+HHMM", "0000").optionalEnd()
.toFormatter();
And the use the OffsetDateTime to parse string representing with offset
A date-time with an offset from UTC/Greenwich in the ISO-8601 calendar system, such as 2007-12-03T10:15:30+01:00.
OffsetDateTime dateTime = OffsetDateTime.parse("2019-11-13T00:11:08+0000", formatter);
OffsetDateTime dateTime = OffsetDateTime.parse("2019-11-13T00:11:08+05:00", formatter);
If you want to convert it into local time zone time LocalDateTime then use atZoneWithSameInstant()
LocalDateTime local = dateTime.atZoneSameInstant(ZoneId.of("America/New_York")).toLocalDateTime()
Note : Don't use SimpleDateFormat and util.Date which are legacy old framework
I'm trying to convert a String value (initially a LocalDateTime variable) that was stored in a database (as datetime) and parse it into a LocalDateTime variable. I've tried it with a formatter:
String dTP;
dTP=(rs.getString("arrivedate"));
DateTimeFormatter formatter = DateTimeFormatter.ISO_LOCAL_DATE_TIME;
LocalDateTime dateTimeParked = LocalDateTime.parse(dTP,formatter);
And without a formatter:
String dTP;
dTP=(rs.getString("arrivedate"));
LocalDateTime dateTimeParked = LocalDateTime.parse(dTP);
But I get the same error each time:
Exception in thread "AWT-EventQueue-0" java.time.format.DateTimeParseException: Text '2016-07-09 01:30:00.0' could not be parsed at index 10
My thinking is that index 10 is the space between date and time.
Could anyone help me with this? I've been at it for hours :(
There is a error in the format of the that causes the issue. Please refer https://docs.oracle.com/javase/8/docs/api/java/time/format/DateTimeFormatter.html.The ISO date time is of the format '2011-12-03T10:15:30' . The following will give you the idea
public static void main(String[] args) throws Exception {
String isoDate = "2016-07-09T01:30:00.0";
// ISO Local Date and Time '2011-12-03T10:15:30'
DateTimeFormatter formatter = DateTimeFormatter.ISO_LOCAL_DATE_TIME;
LocalDateTime dateTimeParked = LocalDateTime.parse(isoDate, formatter);
System.out.println(dateTimeParked);
String date = "2016-07-09 01:30:00.0";
DateTimeFormatter formatterNew = DateTimeFormatter.ofPattern("yyyy-LL-dd HH:mm:ss.S");
LocalDateTime dateTimeParkedNew = LocalDateTime.parse(date, formatterNew);
System.out.println(dateTimeParkedNew);
}
This prints :
2016-07-09T01:30
2016-07-09T01:30
The other answers are correct, your string is in SQL format which differs from the canonical version of ISO 8601 format by using a space character in the middle rather than a T. So either replace the space with a T or define a formatting pattern for parsing.
Use smart objects, not dumb strings
But the bigger problem is that you are retrieving the date-time value from your database as a string. You should be retrieving date-time types of data as date-times types in Java.
For drivers compliant with JDBC 4.2 and later, you should be able to use setObject and getObject with java.time objects.
For SQL type of TIMESTAMP WITHOUT TIME ZONE use LocalDateTime. For TIMESTAMP WITH TIME ZONE, use Instant or perhaps ZonedDateTime depending on the database.
LocalDateTime ldt = myResultSet.getObject( … , LocalDateTime.class );
Store in database.
myPreparedStatement.setObject( … , ldt ) ;
try this formatter:
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss.S");
I'm not sure about the millisecond part though (In case it is more than 1 character long).
I'm using Joda time DateTimeFormatter to create a new datetime object in yyyy-mm-dd string format. When calling DateTime date = formatter.parse(String) I get a DateTime object with an extra hour. I live in UTC +1. How to format a string datetime without hours added.
String date = "2013-01-28";
DateTimeFormatter formatter = DateTimeFormat.forPattern("yyyy-mm-dd");
DateTime date = formatter.parseDateTime(date);
date.ToString() = 2013-01-28T00:01:00.000+01:00
expected = 2013-01-28T00:00:00.000+01:00
Additionally, later in the code I compare two DateTime objects. This parser is in yymmdd format and it does not add one hour.
String date = "130102"
DateTimeFormatter format = DateTimeFormat.forPattern("yyMMdd");
DateTime datetime = format.parseDateTime(date);
datetime.toString = 2013-01-02T00:00:00.000+01:00
yyyy-mm-dd uses the minute-of-hour, not the month (pattern symbol M). Please refer to the documentation of pattern symbols on Joda-Time-page.
Parsing "2013-01-28" with your wrong pattern yields "2013-01-28T00:01:00.000+01:00". Do you see the minute equal to 1? And the month of January seems to be a default value if the parser cannot find a month information (in my opinion not smart).