LocalDate - How to remove character 'T' in LocalDate - java

How to remove T in my localDate?
I need to remove the 'T' to match data in my database.
This is my code
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss", Locale.US);
String strLocalDate = patientDiagnosisByDoctor.getDiagnosisDateTime().toLocalDateTime().toString();
LocalDateTime localDate = LocalDateTime.parse(strLocalDate, formatter);
System.out.println(localDate);
I got this output:
2015-10-23T03:34:40
What is the best way to remove the 'T' character? Any idea guys?

What is the best way to remove the 'T' character? Any idea guys?
Use a DateTimeFormatter to format the value of LocalDateTime the way you want it...
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss", Locale.US);
String strLocalDate = "2015-10-23T03:34:40";
LocalDateTime localDate = LocalDateTime.parse(strLocalDate, formatter);
System.out.println(localDate);
System.out.println(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss").format(localDate));
System.out.println(DateTimeFormatter.ofPattern("HH:mm:ss yyyy-MM-dd ").format(localDate));
Which prints...
2015-10-23T03:34:40
2015-10-23 03:34:40
03:34:40 2015-10-23
Remember, date/time objects are just a container for amount of time which has passed since a fixed point in time (like the Unix epoch), they don't have a internal/configurable format of their own, they tend to use the current locale's format.
Instead, when you want to present the date/time value, you should first use a DateTimeFormatter to format the date/time value to what ever format you want and display that
I need to remove the 'T' to match data in my database.
Opps, missed that part.
In this case, you should be converting your Date/Time values to use java.sql.Timestamp and using a PreparedStatement to insert/update them

String localTime = "2018-09-13 00:00:00";
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss", Locale.ENGLISH);
LocalDateTime date = LocalDateTime.parse(localTime, formatter);
String replace = date.toString().replace("T", " ");
System.out.println(replace);
2018-09-13 00:00

Simple option using the Joda-Time library.
new LocalDateTime(DateTimeZone.forID("Europe/London")).toString().replace("T", " ");

Related

error java.time.format.DateTimeParseException: Text '2020-10-16T18:04:59+0300' could not be parsed at index 24

I´m trying to pase the next String using LocalDateTime, but I always get de unparsed text found error:
java.time.format.DateTimeParseException: Text '2020-10-16T18:04:59+0300' could not be parsed at index 24
Need: from 2020-10-16T18:04:59+0300 to 2020-10-16 18:04.
My code:
public String getFormattingData(String sourceData) {
DateTimeFormatter sourceFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ssZ''e", Locale.ENGLISH);
DateTimeFormatter newFormatter = DateTimeFormatter.ofPattern("dd-MM-yyy HH:mm", Locale.ENGLISH);
LocalDate date = LocalDate.parse("2020-10-16T18:04:59+0300", sourceFormatter);
return newFormatter.format(date);
}
What am I doing wrong?
See the related question: Format a date using the new date time API
The source format you are looking for is: "yyyy-MM-dd'T'HH:mm:ssZ" (as mentioned by #Sweeper in his comment)
If you want the HH:mm in the output format, you need to use a LocalDateTime rather than a LocalDate
The code below works for me:
public String getFormattingData(String sourceData) {
DateTimeFormatter sourceFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ssZ", Locale.ENGLISH);
DateTimeFormatter newFormatter = DateTimeFormatter.ofPattern("dd-MM-yyyy HH:mm", Locale.ENGLISH);
LocalDateTime date = LocalDateTime.parse("2020-10-16T18:04:59+0300", sourceFormatter);
return newFormatter.format(date);
result:
16-10-2020 18:04
You just need to correct the date pattern of source date like this:
public static String formatDate(String strDate, String srcPattern, String tgtPattern) {
DateTimeFormatter srcFormatter = DateTimeFormatter.ofPattern(srcPattern, Locale.ENGLISH);
DateTimeFormatter tgtFormatter = DateTimeFormatter.ofPattern(tgtPattern, Locale.ENGLISH);
return tgtFormatter.format(LocalDateTime.parse(strDate, srcFormatter));
}
You can also use SimpleDateFormat:
public static String formatDate(String strDate, String srcPattern,
String tgtPattern) throws ParseException {
SimpleDateFormat srcFormatter = new SimpleDateFormat(srcPattern, Locale.ENGLISH);
SimpleDateFormat tgtFormatter = new SimpleDateFormat(tgtPattern, Locale.ENGLISH);
return tgtFormatter.format(srcFormatter.parse(strDate));
}
And then call it with any pattern that you want:
System.out.println(formatDate("2020-10-16T18:04:59+0300", "yyyy-MM-dd'T'HH:mm:ssZ", "dd-MM-yyy HH:mm"));
Don’t write a method that converts a date and time from a string in one format to a string in a different format. In your program keep dates and times as proper date-time objects. Just like you don’t keep numbers and Boolean values in strings (I hope!) When you receive string input, parse into a date-time object at once. Only when you need to give string output, format into an appropriate string.
When I receive a string containing date, time and UTC offset, like yours does, I prefer to parse it into a OffsetDateTime so I get all the information. It’s easier to throw unneeded information away later than to invent the information that we neglected to parse. Also a LocalDate will not work for your purpose since it doesn’t contain time of day. So you cannot format one into 2020-10-16 18:04 format.
For parsing your string I would use:
DateTimeFormatter formatter = new DateTimeFormatterBuilder()
.append(DateTimeFormatter.ISO_LOCAL_DATE)
.appendLiteral('T')
.append(DateTimeFormatter.ISO_LOCAL_TIME)
.appendOffset("+HHmm", "Z")
.toFormatter();
String sourceData = "2020-10-16T18:04:59+0300";
OffsetDateTime dateTime = OffsetDateTime.parse(sourceData, formatter);
System.out.println(dateTime);
Output is:
2020-10-16T18:04:59+03:00
The definition of the formatter is longish but has the advantage of reusing predefined formatters for date and time.
For displaying a formatted date and time to the user, don’t you want to use the user’s time zone rather then the offset that happened to be in the string (+03:00 in your case)?
ZoneId zone = ZoneId.of("Antarctica/South_Pole");
DateTimeFormatter newFormatter = DateTimeFormatter.ofPattern("dd-MM-yyyy HH:mm", Locale.ENGLISH);
String formatted = dateTime.atZoneSameInstant(zone).format(newFormatter);
System.out.println(formatted);
17-10-2020 04:04
What went wrong in your code?
As others have said, yyyy-MM-dd'T'HH:mm:ssZ in your format pattern string for parsing parses your entire date-time string of 2020-10-16T18:04:59+0300 nicely. The ''e at the end of the format pattern is the culprit. This would require an additional single quote (apostrophe) and the number of the day of the week to be present (pattern letter e is for localized day of week). Since Java had successfully parsed 24 chars and then failed to parse an apostrophe, it threw the exception mentioning thst the string could not be parsed at index 24.

Parsing and formatting LocalDate with unnecessary time and timezone

Edit :
I opened a bug and it has been confirmed by Oracle. You can follow the resolution here : https://bugs.java.com/bugdatabase/view_bug.do?bug_id=JDK-8216414
I'm interfacing with a LDAP repository which store the birthdate of a person with the time and timezone like this :
If the birthdate is "27-12-2018", then the LDAP string is "20181227000000+0000".
I cannot find a way to parse AND format the birthdate using the same pattern.
The following code works well for formatting but not for parsing :
LocalDate date = LocalDate.of(2018, 12, 27);
String pattern = "yyyyMMdd'000000+0000'";
DateTimeFormatter birthdateFormat = DateTimeFormatter.ofPattern(pattern);
// Outputs correctly 20181227000000+0000
date.format(birthdateFormat);
// Throw a DatetimeParseException at index 0
date = LocalDate.parse("20181227000000+0000", birthdateFormat);
And the following code works well for parsing but not for formatting
LocalDate date = LocalDate.of(2018, 12, 27);
String pattern = "yyyyMMddkkmmssxx";
DateTimeFormatter birthdateFormat = DateTimeFormatter.ofPattern(pattern);
// Throws a UnsupportedTemporalTypeException for ClockHourOfDay not supported
// Anyway I would have an unwanted string with non zero hour, minute, second, timezone
date.format(birthdateFormat);
// Parse correctly the date to 27-12-2018
date = LocalDate.parse("20181227000000+0000", birthdateFormat);
Which pattern could satisfy both parsing and formating ?
Am I forced to use 2 different patterns ?
I am asking because the pattern is configured in a property file. I want to configure 1 pattern only in this property file. I would like to externalize the pattern because the LDAP is not part of my project, it is a shared resource and I have no guarantee that the format cannot change.
Since your LDAP string has zoned format ...+0000, I would suggest using ZonedDateTime or OffsetDateTime.
This pattern yyyyMMddHHmmssZZZ would do the trick for both parsing and formatting.
LocalDate date = LocalDate.of(2018, 12, 27);
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyyMMddHHmmssZZZ");
Formatting
First convert your LocalDate to ZonedDateTime/OffsetDateTime:
ZonedDateTime zonedDateTime = date.atStartOfDay(ZoneOffset.UTC);
// or
OffsetDateTime offsetDateTime = date.atStartOfDay().atOffset(ZoneOffset.UTC);
Then format it:
// Both output correctly 20181227000000+0000
System.out.println(zonedDateTime.format(formatter));
// or
System.out.println(offsetDateTime.format(formatter));
Parsing
First parse the ZonedDateTime/OffsetDateTime:
// Both parse correctly
ZonedDateTime zonedDateTime = ZonedDateTime.parse("20181227000000+0000", formatter);
// or
OffsetDateTime offsetDateTime = OffsetDateTime.parse("20181227000000+0000", formatter);
Once you have ZonedDateTime/OffsetDateTime, you can simply retrieve the LocalDate like this:
LocalDate date = LocalDate.from(zonedDateTime);
// or
LocalDate date = LocalDate.from(offsetDateTime);
Update
Both parsing and formatting can be simplified to one-liners:
LocalDate date = LocalDate.from(formatter.parse(ldapString));
String ldapString = OffsetDateTime.of(date, LocalTime.MIN, ZoneOffset.UTC).format(formatter);
In case you're still unsatisfied with the code above then you can extract the logic to utility methods:
public LocalDate parseLocalDate(String ldapString) {
return LocalDate.from(formatter.parse(ldapString));
}
public String formatLocalDate(LocalDate date) {
return OffsetDateTime.of(date, LocalTime.MIN, ZoneOffset.UTC)
.format(formatter);
}
I suggest:
LocalDate date = LocalDate.of(2018, Month.DECEMBER, 27);
String pattern = "yyyyMMddHHmmssxx";
DateTimeFormatter birthdateFormat = DateTimeFormatter.ofPattern(pattern);
// Outputs 20181227000000+0000
String formatted = date.atStartOfDay(ZoneOffset.UTC).format(birthdateFormat);
System.out.println(formatted);
// Parses to 2018-12-27T00:00Z
OffsetDateTime odt = OffsetDateTime.parse("20181227000000+0000", birthdateFormat);
System.out.println(odt);
// Validate
if (! odt.toLocalTime().equals(LocalTime.MIN)) {
System.out.println("Unexpected time of day: " + odt);
}
if (! odt.getOffset().equals(ZoneOffset.UTC)) {
System.out.println("Unexpected time zone offset: " + odt);
}
// Converts to 2018-12-27
date = odt.toLocalDate();
System.out.println(date);
The LDAP string represents both date, time and UTC offset. The good solution is to respect that and generate all of those when formatting (setting time of day to 00:00 and offset to 0) and parsing all of them back (at best also validating them to catch if any surprises should arise). Conversion between LocalDate and OffsetDateTime is straightforward when you know how.
Edit 3: Allowing the pattern to be configured
… the pattern is configured in a property file… I want to configure 1
pattern only in this property file.
… I have no guarantee that the format cannot change.
To take the possibility into account that the pattern may some day not contain time of day and/or no UTC offset use this formatter in the above code:
DateTimeFormatter birthdateFormat = new DateTimeFormatterBuilder()
.appendPattern(pattern)
.parseDefaulting(ChronoField.HOUR_OF_DAY, 0)
.toFormatter()
.withZone(ZoneOffset.UTC);
This defines a default time of day (midnight) and a default offset (0). As long as time and offset are defined in the string from LDAP, the defaults are not used.
If you think it is getting too complicated, using two configured formats, one for formatting and one for parsing, may be the best solution (the least annoying solution) for you.
Edit: Avoiding type conversions
I consider the above the nice solution. However, if you insist an avoiding the conversion from LocalDate to ZonedDateTime using atStartOfDay and from OffsetDateTime using toLocalDate, that is possible through the following hack:
DateTimeFormatter birthdateFormat = new DateTimeFormatterBuilder()
.appendValue(ChronoField.YEAR, 4, 4, SignStyle.NEVER)
.appendValue(ChronoField.MONTH_OF_YEAR, 2, 2, SignStyle.NEVER)
.appendValue(ChronoField.DAY_OF_MONTH, 2, 2, SignStyle.NEVER)
.appendLiteral("000000+0000")
.toFormatter();
// Outputs 20181227000000+0000
String formatted = date.format(birthdateFormat);
System.out.println(formatted);
// Parses into 2018-12-27
date = LocalDate.parse("20181227000000+0000", birthdateFormat);
System.out.println(date);
I am specifying the exact width of each field so that the formatter can know where to separate them in the string when parsing.
Edit 2: Is this a bug in parsing?
I would immediately have expected yyyyMMdd'000000+0000' to work for both formatting and parsing. You may try filing a bug with Oracle and seeing what they say, though I wouldn’t bee too optimistic.
Stupid simple solution:
String s1 = "20181227000000+0000";
DateTimeFormatter yyyyMMdd = DateTimeFormatter.ofPattern("yyyyMMdd");
LocalDate date = LocalDate.parse(s1.substring(0, 8), yyyyMMdd);
System.out.println("date = " + date);
String s2 = date.format(yyyyMMdd) + "000000+0000";
System.out.println("s2 = " + s2);
System.out.println(s1.equals(s2));

Java String to Date object of the format “MM/dd/yyyy HH:mm:ss a”

I need to convert a String containing a date into a date object.
The String will be in the format "yyyy-mm-dd HH:mm:ss" and I want the "MM/dd/yyyy HH:mm:ss a " format as result.
String dateString = "2018-03-20 09:31:31";
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("MM/dd/yyyy HH:mm:ss a",
Locale.ENGLISH);
LocalDate date = LocalDate.parse(dateString , formatter);
The code above is throwing an exception.
You have to use two Formatter, one to covert String to LocalDateTime and the other to format this date as you want :
From String to LocalDateTime :
String dateString = "2018-03-20 09:31:31";
LocalDateTime date = LocalDateTime.parse(
dateString,
DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss", Locale.ENGLISH)
);
Now From LocalDateTime to String :
DateTimeFormatter formatter = DateTimeFormatter.ofPattern(
"MM/dd/yyyy HH:mm:ss a", Locale.ENGLISH
);
String newDate = date.format(formatter);
System.out.println(newDate);// 03/20/2018 09:31:31 AM
Note : You have to use LocalDateTime instead of just LocalDate, your format contain both date and time, not just date, else you will get an error :
java.time.temporal.UnsupportedTemporalTypeException: Unsupported field: HourOfDay
That's a common error, based on the misconception that dates have formats - but they actually don't.
Date/time objects have only values, and those values - usually numerical - represent the concept of a date (a specific point in the calendar) and a time (a specific moment of the day).
If you have a String, then you don't actually have a date. You have a text (a sequence of characters) that represents a date. Note that all of the strings below are different (they have a different sequence of characters), but all represent the same date (the same values, the same point in the calendar):
2018-03-20 09:31:31
03/20/2018 9:31:31 AM (using USA's format: month/day/year)
Tuesday, March 20th 2018, 09:31:31 am
and many others...
What you want to do is to get one format (one String, one text representing a date) and transform it to another format (anoter String, another different sequence of characters that represents the same date).
In Java (and in many other languages - if not all - btw) you must do it in 2 steps:
convert the String to a date/time object (convert the text to the numerical values) - that's what the parse method does
convert the date/time object to another format (convert the numerical values to another text)
That said, when you call the parse method, you're trying to transform a String (a text, a sequence of characters) into a date/time object. This means that the DateTimeFormatter must have a pattern that matches the input.
The input is 2018-03-20 09:31:31, which is year-month-day hour:minute:second. And the formatter you used to parse it has the pattern MM/dd/yyyy HH:mm:ss a (month/day/year hour:minute:second am/pm).
You used the output pattern (the one that should be used in step 2) to parse the input. That's why you've got an exception: the formatter tried to parse a month with 2 digits followed by a / when the input actually contains a year with 4 digits followed by a -.
You must use a different DateTimeFormatter for each step, using the correct pattern for each case. YCF_L's answer has the code that does the job, I'd just like to add one little detail. The formatter used for the output (step 2) is:
DateTimeFormatter formatter = DateTimeFormatter.ofPattern(
"MM/dd/yyyy HH:mm:ss a", Locale.ENGLISH
);
Note that HH is used for the hours. Take a look at the javadoc and you'll see that uppercase HH represents the hour-of-day fields (values from 0 to 23 - so 1 AM is printed as 01 and 1 PM is printed as 13).
But you're also printing the AM/PM field (the a in the pattern), so maybe what you need is actually the lowercase hh, which is the clock-hour-of-am-pm (values from 1 to 12) or even KK (hour-of-am-pm (values from 0 to 11)).
String dateString = "2018-03-20 09:31:31";
SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
try {
Date date = formatter.parse(dateInString);
DateFormat df = new SimpleDateFormat("MM/dd/yyyy HH:mm:ss");
String reportDate = df.format(date );
} catch (ParseException e) {
e.printStackTrace();
}
You need to do a 2 steps conversion:
from your String date time in the wrong format to a (tempoary) LocalDateTime object.
if you still want to only extract the date (Year-Month-day) do a LocalDateTime.toLocalDate()
From this LocalDateTime object into the your String object in the right format
String dateString = "2018-03-20 09:31:31";
DateTimeFormatter formatterForWrongFormat = new DateTimeFormatterBuilder()
.append(DateTimeFormatter.ISO_LOCAL_DATE)
.appendLiteral(" ")
.append(DateTimeFormatter.ISO_LOCAL_TIME)
.toFormatter();
//1- from String(wrong format) into datetime object
LocalDateTime dateTime = LocalDateTime.parse(dateString , formatterForWrongFormat);
// 1.1 extract date object (Optional)
LocalDate myDate = dateTime.toLocalDate();
// 2- now from your LocalDateTime to the String in the RIGHT format
DateTimeFormatter formatterForRightFormat = DateTimeFormatter.ofPattern("MM/dd/yyyy HH:mm:ss a",
Locale.ENGLISH);
System.out.println("right format: "+dateTime.format(formatterForRightFormat));
you can test this code here
You can use the SimpleDateFormatter which is easier to implement and permit you to change the format of your date easily.
More here : What are the date formats available in SimpleDateFormat class?
Hope this will help you !

Parse datetime without offset in OffsetDateTime java

Can I somehow parse a datetime that's without offset using OffsetDateTime.parse(....)
Java code:
DateTimeFormatter FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss.SSS XXX");
OffsetDateTime date = OffsetDateTime.parse("2017-02-03 12:30:3000", FORMATTER);
I'm getting datetime as a String without offset, but need to parse it into OffsetDateTime, I know I need an offset here, but can I some how alter that String to insert default/dummy offset (maybe +00:00) & parse it using OffsetDateTime. The problem is that object has to be OffsetDateTime.
The simplest solution is to parse your string into a LocalDateTime and then convert:
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("uuuu-MM-dd HH:mm:ss");
OffsetDateTime date = LocalDateTime.parse("2017-02-03 12:30:30", formatter)
.atOffset(ZoneOffset.UTC);
This gives an OffsetDateTime of 2017-02-03T12:30:30Z, where Z means UTC or offset zero.
You can parse directly into an OffsetDateTime if you want:
DateTimeFormatter FORMATTER = new DateTimeFormatterBuilder()
.appendPattern("yyyy-MM-dd HH:mm:ss")
.parseDefaulting(ChronoField.OFFSET_SECONDS, 0)
.toFormatter();
OffsetDateTime date = OffsetDateTime.parse("2017-02-03 12:30:30", FORMATTER);
Finally, if you are required to use the formatter given in the question, altering the string to fit is of course an option. For example:
DateTimeFormatter FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss.SSS XXX");
String fixedDateTimeString
= "2017-02-03 12:30:3000".replaceFirst("(\\d{2})0*$", "$1.000 +00:00");
OffsetDateTime date = OffsetDateTime.parse(fixedDateTimeString, FORMATTER);
As you can see, in the last example I have also kept the too many zeroes in the string I am using as a starting point, removing them in the same operation that appends the offset. The result is the same, 2017-02-03T12:30:30Z.
Edit: uuuu or yyyy for year in the format pattern string? Since the year is always in the common era (Anno Domini), either works. yyyy is for year of era and would be right of there was an era designator (like AD or BC, format pattern letter G). uuuu is a signed year, where year 0 means 1 BCE, -1 means 2 BCE, etc. There’s more in this question: uuuu versus yyyy in DateTimeFormatter formatting pattern codes in Java?
Actually I achieved it by:
DateTimeFormatter FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss.SSS");
OffsetDateTime.of(LocalDateTime.parse("2017-02-03 12:30:30", FORMATTER), ZoneOffset.UTC);

how to get time stamp for the example: 2016-08-29T09:15:17Z?

I have tried to get the date format 2016-08-29T09:15:17Z but not able to get the trailing Z at the end.
I also checked the date time documentation at official website but could not find a similar pattern. So far the date format I have created is as follows:
yyyy-MM-dd'T'HH:mm:ss.SSSZ
So far the code I have written is:
public static void main(String args[]) throws ParseException{
Date nDate=new Date();
//SimpleDateFormat format=new SimpleDateFormat("ddMMYYYYHHMMSS");
String date=new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSZ").format(nDate);
System.out.println(date);
}
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 -
TimeZone timeZone = TimeZone.getTimeZone("UTC"); // optional
DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'"); // Quoted "Z" to indicate UTC, no timezone offset
dateFormat.setTimeZone(timeZone); // optional
String date = dateFormat .format(new Date()); // date will have the required format
System.out.println(date);
Z is a constant value like T in your string, so you have to put single quotes arround it:
String date=new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'").format(nDate);
If you use Z without single quotes DateFormat expect the timezone value
Oracle Documentation describe that z and Z both are use for time zone.
So if you don't want special meaning of Z then you need to write like :
yyyy-MM-dd'T'HH:mm:ss'Z'
I am adding another way to do it, using the new java.time API introduced from JDK 8 onwards.
LocalDateTime nDate=LocalDateTime.now();
DateTimeFormatter formatter = new DateTimeFormatterBuilder()
.append(DateTimeFormatter.ISO_LOCAL_DATE)
.appendLiteral('T')
.append(DateTimeFormatter.ISO_LOCAL_TIME)
.appendLiteral('Z')
.toFormatter();
String date = formatter.format(nDate);
System.out.println(date);

Categories