I have a date '2021-06-19 14:57:23.0' which I need to change it to LocalDateTime type. When I parse, it throws Text could not be parsed at index 10.
String date = "2021-06-19 14:57:23.0";
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSS");
LocalDateTime date = LocalDateTime.parse(date, formatter);
What am I missing here? I have a string in a format which I am converting to a different format by specififying. Any advise would be appreciated. Thanks
You have the wrong pattern for your date. The right pattern for you would be:
String date = "2021-06-19 14:57:23.0"; // declaring the date variable
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss.S"); // declaring the pattern. Here was your error.
LocalDateTime date = LocalDateTime.parse(date, formatter);
Two points that have more or less been covered in the comments, but which I thought deserved to go into an answer:
A LocalDateTime hasn’t got, as in cannot have a format.
To change from one string format to another you generally need two formatters, one for parsing the format that you have got and one for formatting into the desired format.
So you will need to decide whether you need a LocalDateTime or you need the format that you specified since you cannot have both in the same object. But: in your particular case you can almost. Stealing the code from the answer by Ctrl_see:
String dateString = "2021-06-19 14:57:23.0";
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("uuuu-MM-dd HH:mm:ss.S");
LocalDateTime dateTime = LocalDateTime.parse(dateString, formatter);
System.out.println("Parsed date and time: " + dateTime);
Output is:
Parsed date and time: 2021-06-19T14:57:23
Only the three decimals that you asked for were not output. The format that we get from LocalDateTime.toString() (implicitly called when we concatenate the LocalDateTime to a string) is ISO 8601, and according to the ISO 8601 standard the decimals are optional when they are 0. So please check if the above isn’t fine for your purpose.
If you do need the decimals, as I said, we will need a second formatter to format back into a string having the desired format:
DateTimeFormatter targetFormatter
= DateTimeFormatter.ofPattern("uuuu-MM-dd'T'HH:mm:ss.SSS");
String formattedDateTimeString = dateTime.format(targetFormatter);
System.out.println(formattedDateTimeString);
2021-06-19T14:57:23.000
Links
Wikipedia article: ISO 8601
My answer to a related question about date-time objects with a format
Related
String is in this format - "2021-07-13 05:22:18.712"
I tried using this code to parse it.
OffsetDateTime parsedDateTime = OffsetDateTime.parse("2021-07-13 05:22:18.712");
But i keep getting this error -
org.threeten.bp.format.DateTimeParseException: Text '2021-07-13 05:22:18.712' could not be parsed at index 10.
How do i make it work? Any suggestions will be helpful. Thanks
You need to decide on a time zone (or at least on an offset, but time zone is usually the correct means). And then you need to use a formatter that defines the format that you are trying to parse:
private static final DateTimeFormatter FORMATTER = new DateTimeFormatterBuilder()
.append(DateTimeFormatter.ISO_LOCAL_DATE)
.appendLiteral(' ')
.append(DateTimeFormatter.ISO_LOCAL_TIME)
.toFormatter(Locale.ROOT);
With this formatter it’s a pretty simple operation:
ZoneId zone = ZoneId.of("Asia/Kolkata");
String input = "2021-07-13 05:22:18.712";
OffsetDateTime dateTime = LocalDateTime.parse(input, FORMATTER)
.atZone(zone)
.toOffsetDateTime();
System.out.println(dateTime);
Output from the example snippet is:
2021-07-13T05:22:18.712+05:30
Since as #Sweeper noted in a comment your string does not contain UTC offset nor time zone, parse it into a LocalDateTime first. The Local in some java.time class names means without time zone or UTC offset. Then convert into a ZonedDateTime in the intended time zone and further into the desired type, OffsetDateTime.
If you want to use the default time zone of the JVM, set zone to ZoneId.systemDefault(). Be aware that the default time zone may be changed at any time from another part of your program or another program running in the same JVM, so this is fragile.
Possible shortcuts
My formatter is wordy because I wanted to reuse as much as I could from built-in formatters. If you don’t mind building the formatter by hand from a pattern, you may use:
private static final DateTimeFormatter FORMATTER
= DateTimeFormatter.ofPattern("uuuu-MM-dd HH:mm:ss.SSS", Locale.ROOT);
Or even shorter, you may hand substitute the space in your string with a T to obtain ISO 8601 format and then parse into a LocalDateTime without specifying any formatter at all.
What went wrong in your code?
The exception message you got is trying to be helpful:
But i keep getting this error -
org.threeten.bp.format.DateTimeParseException: Text '2021-07-13
05:22:18.712' could not be parsed at index 10.
Index 10 in your string is where the space between date and time is. The one-arg OffsetDateTime.parse method expects ISO 8601 format, like 2021-07-13T05:22:18.712+05:30, so with a T to denote the start of the time part and with a UTC offset at the end. The absence of the T caused your exception. Had you fixed that, you would have got another exception because of the missing UTC offset.
Link
Wikipedia article: ISO 8601
You first need to check the document.
It indicates parse need to go with a date format such as 2007-12-03T10:15:30 +01:00.
You date is missing a "T", "2021-07-13 05:22:18.712". Hence it did not go well, counting it from index 0, it's character at 10.
If you need to parse 2021-07-13T05:22:18.712, you will still get error. An error Text '2021-07-13T05:22:18.712' could not be parsed at index 23. Which is the problem of miliseconds.
So a big round to go:
//Format to date
SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS");
//Format to new string
SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssX");
java.util.Date date1=simpleDateFormat.parse("2021-07-13 05:22:18.712");
String newDate = formatter.format(date1);
//finally.
OffsetDateTime parsedDateTime = OffsetDateTime.parse(newDate);
i wrote an util function to convert a string time value of format 2018-11-26T15:12:03.000-0800 to localdatetime of format "M/dd/yy HH:mm:ss a z"
string of format 2018-11-26T15:12:03.000-0800 to java.time.localdatetime of format "M/dd/yy HH:mm:ss a z" conversion throwing exception.
public static LocalDateTime convertStringToTime(String time){
String pattern = "M/dd/yy HH:mm z";
DateTimeFormatter formatter = DateTimeFormatter.ofPattern(pattern);
ZonedDateTime zonedDateTime = ZonedDateTime.parse(time,formatter);
return zonedDateTime.toLocalDateTime();
}
which gives me the below exception
java.time.format.DateTimeParseException: Text '2018-11-26T12:45:23.000-0800' could not be parsed at index 4
at java.time.format.DateTimeFormatter.parseResolved0(DateTimeFormatter.java:1947)
You say that you want: a LocalDateTime of format M/dd/yy HH:mm:ss a z. This is impossible for three reasons:
A LocalDateTime cannot have a format. Its toString method always returns a string like 2018-11-26T15:12:03 (ISO 8601 format), there is no way we can change that. You also shouldn’t want a LocalDateTime with a specific format; I include a link at the bottom explaining why not.
I assume that by z in your format you mean time zone abbreviation like PDT for Pacific Daylight Time. A LocalDateTime neither has UTC offset not time zone, so this doesn’t make sense.
Your input time string doesn’t hold any time zone either, only an offset from UTC. So to print a time zone abbreviation, you will first need to choose a time zone.
Instead I suggest:
ZoneId zone = ZoneId.of("America/Whitehorse");
DateTimeFormatter inputFormatter
= DateTimeFormatter.ofPattern("uuuu-MM-dd'T'HH:mm:ss.SSSXX");
DateTimeFormatter desiredFormatter
= DateTimeFormatter.ofLocalizedDateTime(FormatStyle.SHORT, FormatStyle.LONG)
.withLocale(Locale.US);
String time = "2018-11-26T15:12:03.000-0800";
OffsetDateTime dateTime = OffsetDateTime.parse(time, inputFormatter);
String formattedDateTime = dateTime.atZoneSameInstant(zone)
.format(desiredFormatter);
System.out.println("Converted format: " + formattedDateTime);
Output is:
Converted format: 11/26/18, 3:12:03 PM PST
To convert date and time from a string in one format to a string in another format you generally need two DateTimeFormatters: one specifying the format of the string you’ve got and one specifying the format that you want.
Rather than building your own formatter from a format pattern string, rely on built-in formats when you can. In our case I specify FormatStyle.SHORT for the date (giving two-digit-year) and FormatStyle.LONG for the time, giving us the time zone abbreviation.
The idea of relying on built-in formats can be taken one step further. The string you’ve got is in ISO 8601 format, so we just need to piece two pieces together:
DateTimeFormatter inputFormatter = new DateTimeFormatterBuilder()
.append(DateTimeFormatter.ISO_LOCAL_DATE_TIME)
.appendOffset("+HHmm", "Z")
.toFormatter();
It’s longer, but it’s less error-prone.
Links
Wikipedia article: ISO 8601.
My answer to want current date and time in “dd/MM/yyyy HH:mm:ss.SS” format explaining why you don’t want a date-time object with a format.
This question already has answers here:
Convert a date format in epoch
(6 answers)
Closed 5 years ago.
I am very new to Java and coding in general - I have some code which returns a timestamp in the following format yyyy.MM.dd HH:mm:ss:ms which is shown below:
SimpleDateFormat formatter = new SimpleDateFormat("yyyy.MM.dd HH:mm:ss:sss");
This returns:
2017.07.19 11:42:30:423
Is there a way to edit the "SimpleDateFormat formatter" code above to return the date/time as an epoch timestamp that includes milliseconds so that the value returned is formatted as per the below?
1500464550423
I'm hoping that I can amend the ("yyyy.MM.dd HH:mm:ss:sss") part of the SimpleDateFormat formatter code to do this.
Any help or advice is much appreciated.
Thanks
You have a simple error in the use of case in your format pattern string (these are case sensitive). And worse, you are using the old and troublesome SimpleDateFormat class. One of the many problems with it is it’s not telling you what the problem is.
So I recommend you use the modern Java date and time API instead (I am deliberately using your format pattern string verbatim):
String receivedTimetamp = "2017.07.19 11:42:30:423";
DateTimeFormatter parseFormatter
= DateTimeFormatter.ofPattern("yyyy.MM.dd HH:mm:ss:sss");
LocalDateTime dateTime = LocalDateTime.parse(receivedTimetamp, parseFormatter);
System.out.println(dateTime);
This code throws an IllegalArgumentException: Too many pattern letters: s. I hope this calls your awareness to the fact that you are using two s’s for seconds and three s’s for fraction of second. If it still isn’t clear, the documentation will tell you that lowercase s is correct for seconds, while you need uppercase S for the fraction. Let’s repair:
DateTimeFormatter parseFormatter
= DateTimeFormatter.ofPattern("yyyy.MM.dd HH:mm:ss:SSS");
Now the code prints 2017-07-19T11:42:30.423, so we have managed to parse the string correctly.
To convert to milliseconds we are still missing a crucial piece of information: in what time zone should the timestamp be interpreted? I think the two obvious guesses are UTC and your local time zone (which I don’t know). Try UTC:
System.out.println(dateTime.atOffset(ZoneOffset.UTC).toInstant().toEpochMilli());
This produces 1500464550423, which is the number you asked for. I suppose we’re done.
If you wanted your JVM’s time zone setting instead, use .atZone(ZoneId.systemDefault()) instead of .atOffset(ZoneOffset.UTC), but beware that the setting may be altered by other software running in the same JVM, so this is fragile.
First of all, check the documentation of SimpleDateFormat. The pattern that corresponds to milliseconds is an uppercase S, while the lowercase s corresponds to seconds. The problem is that SimpleDateFormat usually doesn't complain and try to parse 423 as seconds, adding this amount to your end date (giving an incorrect result).
Anyway, SimpleDateFormat just parses a String to a java.util.Date or formats the Date to a String. If you want the epoch millis value, you must get it from the Date object:
// input string
String s = "2017.07.19 11:42:30:423";
// use correct format ('S' for milliseconds)
SimpleDateFormat formatter = new SimpleDateFormat("yyyy.MM.dd HH:mm:ss:SSS");
// parse to a date
Date date = formatter.parse(s);
// get epoch millis
long millis = date.getTime();
System.out.println(millis); // 1500475350423
The problem is that SimpleDateFormat uses the system's default timezone, so the final value above (1500475350423) will be equivalent to the specificed date and time in my system's timezone (which can be different from yours - just for the record, my system's default timezone is America/Sao_Paulo). If you want to specify in what timezone this date is, you need to set in the formatter (before calling parse):
// set a timezone to the formatter (using UTC as example)
formatter.setTimeZone(TimeZone.getTimeZone("UTC"));
With this, the result for millis will be 1500464550423 (the equivalent to the specificed date and time in UTC).
To do the opposite (create a date from the millis value), you must create a Date object and then pass it to the formatter (also taking care of setting a timezone to the formatter):
// create date from millis
Date date = new Date(1500464550423L);
// use correct format ('S' for milliseconds)
SimpleDateFormat formatter = new SimpleDateFormat("yyyy.MM.dd HH:mm:ss:SSS");
formatter.setTimeZone(TimeZone.getTimeZone("UTC"));
// format date
String formatted = formatter.format(date);
Java new date/time API
The old classes (Date, Calendar and SimpleDateFormat) have lots of problems and design issues, and they're being replaced by the new APIs.
If you're using Java 8, consider using the new java.time API. It's easier, less bugged and less error-prone than the old APIs.
If you're using Java <= 7, you can use the ThreeTen Backport, a great backport for Java 8's new date/time classes. And for Android, there's the ThreeTenABP (more on how to use it here).
The code below works for both.
The only difference is the package names (in Java 8 is java.time and in ThreeTen Backport (or Android's ThreeTenABP) is org.threeten.bp), but the classes and methods names are the same.
As the input String has no timezone information (only date and time), first I parsed it to a LocalDateTime (a class that represents a date and time without timezone). Then I convert this date/time to a specific timezone and get the millis value from it:
// input string
String s = "2017.07.19 11:42:30:423";
// use correct format ('S' for milliseconds)
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy.MM.dd HH:mm:ss:SSS");
// as the input string has no timezone information, parse it to a LocalDateTime
LocalDateTime dt = LocalDateTime.parse(s, formatter);
// convert the LocalDateTime to a timezone
ZonedDateTime zdt = dt.atZone(ZoneId.of("Europe/London"));
// get the millis value
long millis = zdt.toInstant().toEpochMilli(); // 1500460950423
The value is now 1500460950423, equivalent to the specified date and time in London timezone.
Note that the API uses IANA timezones names (always in the format Region/City, like America/Sao_Paulo or Europe/Berlin).
Avoid using the 3-letter abbreviations (like CST or PST) because they are ambiguous and not standard.
You can get a list of available timezones (and choose the one that fits best your system) by calling ZoneId.getAvailableZoneIds().
You can also use ZoneOffset.UTC constant if you want to use UTC.
To do the opposite, you can get the millis value to create an Instant, convert it to a timezone and pass it to the formatter:
// create Instant from millis value
Instant instant = Instant.ofEpochMilli(1500460950423L);
// use correct format ('S' for milliseconds)
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy.MM.dd HH:mm:ss:SSS");
// convert to timezone
ZonedDateTime z = instant.atZone(ZoneId.of("Europe/London"));
// format
String formatted = z.format(formatter);
First advice is to move to java8 java.time API instead of learning the broken java.date API
then do:
Instant i = Instant.now();
System.out.println(i.toEpochMilli());
in your case you can do:
LocalDateTime myldt = LocalDateTime.parse("2017-06-14 14:29:04",
DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
System.out.println(myldt.toInstant(ZoneOffset.UTC).toEpochMilli());
note that as soon as you play more with the api you will find more ways to achieve the same thing, at the end you will end invoking toEpochMilli
String strDate = "Jun 13 2003 23:11:52.454 UTC";
DateTimeFormatter dtf = DateTimeFormatter.ofPattern("MMM dd yyyy HH:mm:ss.SSS zzz");
ZonedDateTime zdt = ZonedDateTime.parse(strDate,dtf);
System.out.println(zdt.toInstant().toEpochMilli()); // 1055545912454
You can try
long time = System.currentTimeMillis();
If you have a java.util.Date then invoking getTime() will return the number of millis since the epoch. For example:
SimpleDateFormat formatter = new SimpleDateFormat("yyyy.MM.dd HH:mm:ss:sss");
Date dateToBeFormatted = new Date();
// this will print a datetime literal on the above format
System.out.println(formatter.format(dateToBeFormatted));
// this will print the number of millis since the Java epoch
System.out.println(dateToBeFormatted.getTime());
The key point here is that in order to get the number of millis since the epoch you do not need a SimpleDateFormatter because the number of millis since the epoch is a property of the Date.
How do you format your date in ISO 8601? E.g.: 2009-06-15T13:45:30
Is there a standard way of generating it from Java without having to create a DateTimeFormatter with a letter pattern?
I see it used in MS documentation:
Standard Date and Time Format Strings
I think this is the commonly referred to as "ISO" date.
Documented in wikipedia], giving examples such as:
Date: 2017-02-21
Combined date and time in UTC: 2017-02-21T10:26:42+00:00
2017-02-21T10:26:42Z
20170221T102642Z
The one thing to be clear: your examples go without any time zone information; so they should be assumed to be "local time".
In this String, T is just Time component in a standard ISO 8601 date time string represented as <date>T<time>. Wikipedia has a detailed page about this standard format.
In java, you can do this to use it
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'");
sdf.setTimeZone(TimeZone.getTimeZone("GMT"));
I have used GMT here just for example. You can set the time zone according to your need. To get more information about TimeZone here is the docs link
ISO-8601
A single point in time can be represented by concatenating a complete date expression, the letter T as a delimiter, and a valid time expression. For example, "2007-04-05T14:30".
The format of such date is a local date time of ISO 8601, without the time-zone.1 According to Wikipedia, date and time expressed according to ISO 8601 are:
Date: 2017-02-21
Combined date and time in UTC: 2017-02-21T12:34:46+00:00
2017-02-21T12:34:46Z
20170221T123446Z
...
There're several ways to create strings with such format in Java. In Java 8, the easiest way is to use the built-in parsing pattern of LocalDateTime. The reason why I don't use ZonedDateTime is that the time-zone of this date is unknown.
// str -> date
LocalDateTime d = LocalDateTime.parse("2009-06-15T13:45:30");
// date -> str
String text = d.format(DateTimeFormatter.ISO_LOCAL_DATE_TIME);
1 ISO 8601: Time zone designators
Easy ways to obtain ISO 8601 in Java:
static void time() {
final DateTimeFormatter fmt = DateTimeFormatter.ISO_LOCAL_DATE_TIME;
OffsetDateTime.now().truncatedTo(ChronoUnit.SECONDS).format(fmt);
Instant.now().atOffset(ZoneOffset.ofHours(1)).truncatedTo(ChronoUnit.SECONDS).format(fmt);
Instant.now().atOffset(ZoneOffset.UTC).truncatedTo(ChronoUnit.SECONDS).format(fmt);
OffsetDateTime.parse("2007-12-03T10:15:30+01:00").format(fmt);
LocalDateTime.parse("2009-06-15T13:45:30").format(fmt);
}
This question already has answers here:
Converting a date string to a DateTime object using Joda Time library
(10 answers)
Closed 6 years ago.
Is there a way to convert a date in the format "YYYY-MM-dd" to "YYYY-MM-dd HH:mm:ss" using Joda?
Eg: "2016-01-21" to "2016-01-21 00:00:00"
Use DateTimeFormat class from Joda API. It helps you to format the date to the formatting of your choice. You can simply provide the format you want, like in this case you want "YYYY-MM-dd HH:mm:ss". The code below works with JodaTime 2.0 and above.
DateTime date = DateTime.parse("2016-01-21", DateTimeFormat.forPattern("YYYY-MM-dd HH:mm:ss"));
There are two things in play here, first we need to parse the existing string into a DateTime object, which is done via the parse method, it also allows an additional argument, to convert the output into a different format. The longer but easier to understand implementation is given below.
DateTime date = DateTime.parse("2016-01-21");
DateTimeFormatter formatter = DateTimeFormat.forPattern("YYYY-MM-dd HH:mm:ss");
date = formatter.parseDateTime(string);
Your question is not clear:
Do you want to just format "something representing a date" into a string with time of "00:00:00"?
Or are you trying to convert "something representing a date" into "something representing a date+time, with 00:00:00 as time"?
Or are you trying to convert a java.util.Date to a Joda org.joda.time.DateTime by ignoring the original time and set time to 00:00:00?
Or are you trying to convert a string of date with format of "YYYY-MM-dd" to another String with date+time, with 00:00:00 as time?
Or something else?
In Joda, the proper way to represent a date is by LocalDate, and the proper way to represent a "date + time" information (but not a instant of time) is by LocalDateTime. DateTime is representing a instant of time. With these basic understanding:
Answer for Q1:
String result = DateTimeFormat.forPattern("YYYY-MM-dd", myLocalDate);
Answer for Q2:
LocalDateTime result = myLocalDate.toLocalDateTime(LocalTime.MIDNIGHT);
Answer for Q3:
DateTime result = new DateTime(javaUtilDate).withTimeAtStartOfDay();
Answer for Q4:
String result = dateString + " 00:00:00";