It appears that Kotlin is very specific regarding the formats of Date. I am receiving a string in this "Jan 1 2023 12:00AM"
and wanted to convert it into this "2023-01-01 00:00:00.0"
format. I looked around but couldn't find a solution.
fun FormatDateTime(dateTimeString: String): String{
val DATE_FORMAT = DateTimeFormatter.ofPattern("MMM dd uuuu")
var dat = dateTimeString.substring(0, dateTimeString.length-7).trim() //Removing ' 12:00AM' part
val changeDate = LocalDateTime.parse(dat, DATE_FORMAT)
//After getting the date, reformat it again to '2023-01-01 00:00:00.0'
return "" //return formatted date string, currently returning empty string
}
But its failing. The error is as follows - java.time.format.DateTimeParseException: Text 'Jan 1 2023' could not be parsed at index 4
. Is there any way to achieve it?
Made some changes to Slaw's answer and not sure if this going break in which scenarios except if the code runs in distinct geographical locations.
fun convert(input: String): String {
var sanitizedInput = input.replace("\\s+".toRegex(), " ").trim()
return LocalDateTime.parse(sanitizedInput, DateTimeFormatter.ofPattern("MMM d uuuu hh:mma"))
.format(DateTimeFormatter.ofPattern("uuuu-MM-dd HH:mm:ss.S"))
}
You're using the MMM dd uuuu
pattern to parse the input string. The dd
means it expects single-digit days to be padded by a leading 0
. But your example input, Jan 1 2023 12:00AM
, does not have that padding. Hence the error at index 4. You should be using d
instead of dd
.
You should also consider parsing the entire input string instead of a substring. Then use the truncatedTo
API of the LocalDateTime
object to set the time to zero. I assume this is what you want since you're currently trying to drop the time value from the input string (via the substring
call) and your example output still has its time as midnight. If you don't want this then remove the truncatedTo
call in the example below.
Based on your question, the following example meets your needs:
import java.time.LocalDateTime
import java.time.format.DateTimeFormatter
import java.time.temporal.ChronoUnit
import java.util.Locale
val INPUT_FORMAT = DateTimeFormatter.ofPattern("MMM d uuuu hh:mma", Locale.US)
val OUTPUT_FORMAT = DateTimeFormatter.ofPattern("uuuu-MM-dd HH:mm:ss.S", Locale.US)
fun main() {
val input = "Jan 1 2023 12:00AM"
println("$input => ${convert(input)}")
}
fun convert(input: String): String {
return LocalDateTime.parse(input, INPUT_FORMAT)
.truncatedTo(ChronoUnit.DAYS)
.format(OUTPUT_FORMAT)
}
Output:
Jan 1 2023 12:00AM => 2023-01-01 00:00:00.0
I explicitly specified the locale so that the localizable parts of the input string ("Jan", "AM"/"PM") are properly parsed. I chose Locale.US
for the example, but you can use any locale that uses the right values for MMM
and a
. Or even let the locale be determined by configuration at run-time.
You could rely on the system default locale, but then your code is likely to break on computers with different locales than your test computer.
Note an alternative to truncatedTo(ChronoUnit.DAYS)
is with(LocalTime.MIDNIGHT)
.