Convert string into LocalDate Kotlin - kotlin

I want to convert string value
this is my code like
val dateFirst = "20 Aug 2012"
val dateSecond = "12/16/2020 12:00:00 AM"
val dateFirstConverted = LocalDate.parse(dateFirst, DateTimeFormatter.BASIC_ISO_DATE)
val dateSecondConverted = LocalDate.parse(dateSecond, DateTimeFormatter.BASIC_ISO_DATE)
println(dateFirstConverted)
println(dateSecondConverted)
then i get error like this.
Exception in thread "main" java.time.format.DateTimeParseException: Text '20 Aug 2012' could not be parsed at index 0
at java.time.format.DateTimeFormatter.parseResolved0(DateTimeFormatter.java:1949)
at java.time.format.DateTimeFormatter.parse(DateTimeFormatter.java:1851)
at java.time.LocalDate.parse(LocalDate.java:400)
at App.TryKt.main(try.kt:11)
at App.TryKt.main(try.kt)
can someone help me how to fix this ?

you have problem because the format of the date is not supported, I invite you to read this article https://www.claudebueno.com/programmation/comment-gerer-la-date-et-lheure-avec-kotlin.htm but in your case if you want that the code runs, change the format of date, like this:
import java.time.LocalDateTime
import java.time.format.DateTimeFormatter
import java.time.LocalDate
fun main() {
//example
val current = LocalDateTime.now()
val formatter = DateTimeFormatter.BASIC_ISO_DATE
val formatted = current.format(formatter)
println("Current Date is: $formatted")
//your code
val dates = /*"20 Aug 2012"*/ "20120820"
val datess = LocalDate.parse(dates, DateTimeFormatter.BASIC_ISO_DATE)
println(datess)
}

tl;dr ⇒ You are using the wrong pattern for parsing
Your date String is of the format dd MMM uuuu (a non ISO format) but you are trying to parse it with a DateTimeFormatter.ISO_LOCAL_DATE
Your datetime String is of the format MM/dd/uuuu hh:mm:ss a (non ISO) but you are trying to parse it with a DateTimeFormatter.ISO_LOCAL_DATE, which is at least doubly wrong because that formatter tries to parse an ISO date. Your String is non ISO and contains more information (time of day) than this formatter is able to parse.
There are several built-in DateTimeFormatters, like the one you are currently using, but you need to use a correct one or if there is none, create one that covers your String(s) yourself (either by DateTimeFormatter.ofPattern(...) or by using a DateTimeFormatterBuilder).
Here's a small example for your String examples:
fun main(args: Array<String>) {
// your example Strings
val dateFirst = "20 Aug 2012"
val dateSecond = "12/16/2020 12:00:00 AM"
// you need two different formatters here, your Strings differ in format and content
val firstFormatter = DateTimeFormatter.ofPattern("dd MMM uuuu", Locale.ENGLISH)
val secondFormatter = DateTimeFormatter.ofPattern("MM/dd/uuuu hh:mm:ss a", Locale.ENGLISH)
// then use those according to what you want to parse
val localDate = LocalDate.parse(dateFirst, firstFormatter)
val localDateTime = LocalDateTime.parse(dateSecond, secondFormatter)
// use the built-in formatters for output
println(localDate.format(DateTimeFormatter.ISO_LOCAL_DATE))
println(localDateTime.format(DateTimeFormatter.ISO_LOCAL_DATE_TIME))
}
Output (in ISO):
2012-08-20
2020-12-16T00:00:00

Related

convert LocalDateTime to Date by using kotlin

I have a java.time.LocalDateTime and i want to convert it in java.util.Date
val myLocalDateTime = LocalDateTime.now().plusDays(5)
I want to convert LocalDateTime.now().plusDays(5) to java.util.Date in kotlin.
How Can i do it?
You need to add mandatory information in order to make a LocalDateTime convertable to a java.util.Date…
Before you try, think about if you can use Instant.now(), because the methods for legacy compatibility require Instants as arguments:
fun main() {
// get "now" as Instant
val now = Instant.now()
// print the java.util.Date created from the Instant
println(Date.from(now))
// use the Instant plus 5 days to create another date
val date = Date.from(now.plus(5, ChronoUnit.DAYS))
// create a formatter for the Date
val formatter = SimpleDateFormat("yyyy-MM-dd")
// and print it using the formatter
println(formatter.format(date))
}
Output (some moments ago on my middle-european machine):
Thu Feb 09 15:31:06 CET 2023
2023-02-14
If you really need to use a LocalDateTime, which has no zone or offset, you will have to add one, convert the result (a ZonedDateTime or an OffsetDateTime) toInstant() and create Dates from those…
If it's all about dates (year, month of year, day of month) without time of day, you could simply use a java.time.LocalDate:
fun main() {
// get "today" as LocalDate
val today = LocalDate.now()
// print it using toString() implicitly
println(today)
// add five days
val fiveDaysLater = today.plusDays(5)
// and print it formatted by a prebuilt formatter
println(fiveDaysLater.format(DateTimeFormatter.ISO_LOCAL_DATE))
}
Output:
2023-02-10
2023-02-15

kotlin SimpleDateFormat Unparseable date

How to format date from String in kotlin?
I tried to parse it with a SimpleDateFormat but it always throws an Exception saying Unparseable date: "21 Agt 2022" when I try to parse the String.
This my code:
var spf = SimpleDateFormat("dd MMM yyyy")
val newDate = spf.parse("21 Agt 2022") // <- always error in this line
spf = SimpleDateFormat("yyyy-MM-dd")
val result = newDate?.let { it1 -> spf.format(it1) }.toString()
My app is running on API 21, so can't use a java.time.LocalDate.
You can use java.time and its LocalDate, you have two options so far:
the ThreeTen Android Backport: a library that makes most java.time functionality available, you will have to import it
Android API Desugaring available from Android Gradle Plugin 4.0.0 or higher
The reason for the error is the missing Locale, which would be a problem in java.time as well:
The abbreviation Agt for August is only used in two Locales: Indonesia (where you seem to be from, at least judging from your profile page) and Kenia.
That means you can use your code, you just have to apply an Indonesian Locale:
fun main(args: Array<String>) {
// prepare the locale your input was created in
val indonesia = Locale.forLanguageTag("id-ID")
// use it in your SimpleDateFormat
var spf = SimpleDateFormat("dd MMM yyyy", indonesia)
// parse the value
val newDate = spf.parse("21 Agt 2022")
// print the value
println(newDate)
}
Output:
Sun Aug 21 00:00:00 CEST 2022
This will create a java.util.Date which is in fact more than day of month, month of year and year… It has a time of day, too, but your input String does not contain any. That means it will add one, the start of day, most likely.
Better / Newer / Date only: java.time
fun main(args: Array<String>) {
// your input String
val input = "21 Agt 2022"
// prepare the locale your input uses
val indonesia = Locale.forLanguageTag("id-ID")
// prepare a DateTimeFormatter that considers Indonesian months
val dtf = DateTimeFormatter.ofPattern("dd MMM uuuu", indonesia)
// parse the String using the DateTimeFormatter
val localDate = LocalDate.parse(input, dtf)
// print the result
println(localDate)
}
Output:
2022-08-21

How to get the first value from a list without exceptions in Kotlin?

I have a date value in format "2021-07-14T13:00:00.000+0300" (or similar). I want to convert it to Date. In this case I have to traverse a loop of different formats and check if they fail.
import java.text.*
import java.util.*
val formats = listOf(
"yyyy-MM-dd'T'HH:mm:ss.SSSZ",
"dd.MM.yyyy, EEEE, HH:mm" // And many others.
)
val date = "2021-07-14T13:00:00.000+0300"
val locale = Locale.getDefault()
for (format in formats) {
try {
return SimpleDateFormat(format, locale).parse(date)
} catch (e: ParseException) {
}
}
// If nothing found, return current date.
return Date()
How to convert this for-loop to something like map? So that we can get the first value without exception?
val result = formats.map { ... }
Another option, while still using firstNotNullOfOrNull(), is to use parse() with a ParsePosition object whose properties you can safely ignore when combined with setLenient(false)*.
The advantage of the parse​(String, ParsePosition) version over parse​(String) is that it returns null when it can't parse the date, instead of throwing an error, so the try-catch overhead per iteration can be avoided.
Along with that, since you're defaulting to the current date if all formats fail, you can avoid the nullable Date type result with an Elvis op at the very end.
val result: Date = formats.firstNotNullOfOrNull { format ->
with (SimpleDateFormat(format, locale)) {
setLenient(false) // may not be required, see below
parse(date, ParsePosition(0)) // is null or Date
}
} ?: Date()
Btw, setLenient(false) may not be required because on v15, there's no leniency for SimpleDateFormat.parse() in the docs...but it does behave leniently. Setting it to true above or leaving it out, and parsing a date of "2021-07-14T53:00:00.000+0300" (note the '53') produced Fri Jul 16 02:00:00 UTC 2021. With no leniency, it produces null. The leniency is mentioned on the abstract base class DateFormat.parse(String, ParsePosition) but not for SimpleDateFormat.parse(String, ParsePosition).
So if you're expecting non-pattern-matching dates rather than invalid-but-pattern-matching dates, the above loop could be reduced to:
val result: Date = formats.firstNotNullOfOrNull { format ->
SimpleDateFormat(format, locale).parse(date, ParsePosition(0))
} ?: Date()
Use firstNotNullOfOrNull().
val result: Date? = formats.firstNotNullOfOrNull { format ->
try {
SimpleDateFormat(format, locale).parse(date)
} catch (e: ParseException) {
null
}
}

Kotlin SimpleDateFormat parse wrong timezone

My mobile timezone was GMT+7, I have a code to convert a specific date time(GMT+0) to a specific timezone(GMT+3):
var strDate = "2020-07-10 04:00:00+0000"
var result: Date?
var dateFormatter = SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSSZ")
dateFormatter.timeZone = TimeZone.getTimeZone("Asia/Jerusalem")
result = dateFormatter.parse(strDate)
The problem is result always return "Fri Jul 10 11:00:00 GMT+07:00 2020"
But I expected it will return date object "Fri Jul 10 07:00:00 GMT+03:00 2020", any idea what's wrong with my code?
It's recommended to use java.time and stop using java.util.Date, java.util.Calendar along with java.text.SimpleDateFormat because of problems like this one.
In your code, the target time zone is obviously not applied to the date but it isn't obvious why it isn't.
A different problem might be pattern you are using because your example String does not contain any unit of time smaller than seconds but the pattern tries to consider .SSS (which made the code fail in the Kotlin Playground).
Switch to java.time and handle this with modern classes, such as OffsetDateTime for parsing this String (it doesn't contain information about a specific time zone, just an offset of zero hours) and ZonedDateTime as the target object (this considers a real time zone which may have different offsets depending things like Daylight Saving Time).
You could do it like this:
import java.time.ZoneId
import java.time.ZonedDateTime
import java.time.OffsetDateTime
import java.time.format.DateTimeFormatter
fun main() {
// this example is in UTC (+0000 --> no offset / offset of 0 hours)
var strDate = "2020-07-10 04:00:00+0000"
// create a formatter that can parse Strings of this pattern
// ([] represents optional units to be parsed)
var dateFormatter = DateTimeFormatter.ofPattern("uuuu-MM-dd HH:mm:ss[.SSS]Z")
// and parse the String to an OffsetDateTime using this formatter
var resultOfParsing = OffsetDateTime.parse(strDate, dateFormatter)
// then print the parsed result
println(resultOfParsing)
// create the target time zone
var timeZone = ZoneId.of("Asia/Jerusalem")
// then use the target zone for a zone shift
var jerusalemTime: ZonedDateTime = resultOfParsing.atZoneSameInstant(timeZone)
// and print the result
println(jerusalemTime)
// you could use your formatter defined above for a differently formatted output, too
println(jerusalemTime.format(dateFormatter))
}
which outputs (including all intermediate results):
2020-07-10T04:00Z
2020-07-10T07:00+03:00[Asia/Jerusalem]
2020-07-10 07:00:00.000+0300

how to cast timestamp to get hour HH format in spark scala

I have a csv data file which contains a column of times in such format HH:MM:SS
I am trying to query the csv using spark-sql in order to get the most busy and less busy hours of entrances/exits .
can anyone help me solve this problem ? much appreciated !
here is a sample of my csv file :
emp_name,emp_badge,door_number,date_time,usage_type
Capucine Letellier,28161comp,5,22:36:27,ENTRANCE
Zoé Bonnin de la Lenoir,75976comp,5,01:08:49,ENTRANCE
Henri Potier,66586comp,4,03:13:16,ENTRANCE
Théodore Rodriguez,39004comp,3,20:55:11,ENTRANCE
Christine Bonneau de Rodrigues,23965comp,4,18:45:42,EXIT
You can use the hour(string date) function which returns the hour of the timestamp. Example: hour('2009-07-30 12:58:59') = 12, hour('12:58:59') = 12.
Next, you can calculate the busy hours and less busy hours like this:
import org.apache.spark.sql.expressions.Window
import org.apache.spark.sql.functions._
val rawData = spark.read.csv("data.csv")
// Busy Hours calculation
val windowSpecBusyHours = Window.partitionBy("_c4").orderBy(col("transactions").desc)
val busyHours = rawData
.withColumn("hours", hour(col("_c3")))
.groupBy("_c4", "hours").agg(count("*").alias("transactions"))
.withColumn("dense_rank", dense_rank().over(windowSpecBusyHours))
.select("_c4", "hours", "transactions").where(col("dense_rank") === 1)
busyHours.show(false)
// Less Busy Hours calculation
val windowSpecLessBusyHours = Window.partitionBy("_c4").orderBy(col("transactions").asc)
val lessBusyHours = rawData
.withColumn("hours", hour(col("_c3")))
.groupBy("_c4", "hours").agg(count("*").alias("transactions"))
.withColumn("dense_rank", dense_rank().over(windowSpecLessBusyHours))
.select("_c4", "hours", "transactions").where(col("dense_rank") === 1)
lessBusyHours.show(false)
If your csv contains
string like "HH:MM:ss" then:
val myCsv = spark.read.csv("path/to/csv")
//this one splits you string by : and takes the first part of it
val addHour = myCsv.withColumn("hour", split($"date_time", ":")(0))
timestamp format then:
val myCsv = spark.read.csv("path/to/csv")
// Cast it first to timestamp because csv doesn't keep column format, after that format it to HH
val addHour = myCsv.withColumn("hour", date_format($"date_time".cast("timestamp"), "HH"))
I hope this helped you.
Later edit:
To use $ operator for column you need to import spark implicits:
import spark.implicits._
Now you can use $ instead of col("column_name") function.