I'm a beginner to scala programming and jvm languages. I want to convert a string in yyyy-MM-dd to date format like this:
import java.text.SimpleDateFormat
import java.util.Date
val format = new SimpleDateFormat("yyyy-MM-dd")
def strTodate(stringDate: String): Date = {
format.parse(stringDate)
}
How can I can take care of exception in case strTodate is called on a wrongly formatted string like strTodate("18/03/03") ? I'll like to handle the exception and also print the string
scala has three ways to handle errors.
Option: has None or Some
Try: has Success or Failure
Either: has left or right. Right is always right result.
I prefer Either of all and here is how you can do it as Either[String, Date] where Left is String, Right is Date.
Example,
import java.text.SimpleDateFormat
import java.util.Date
import scala.util.Try
import scala.util.{Failure, Success}
val format = new SimpleDateFormat("yyyy-MM-dd")
def strTodate(stringDate: String): Either[String, Date] = {
Try {
format.parse(stringDate)
} match {
case Success(s) => Right(s)
case Failure(e: ParseException) => Left(s"bad format: $stringDate")
case Failure(e: Throwable) => Left(s"Unknown error formatting : $stringDate")
}
}
val date1 = strTodate("2018-09-26")
println(date1) // Right(Wed Sep 26 00:00:00 PDT 2018)
val date2 = strTodate("2018/09/26")
println(date2) // Left(bad format: 2018/09/26)
Handling exceptions:
import java.io.IOException
import java.text.SimpleDateFormat
import java.util.Date
object app {
val format = new SimpleDateFormat("yyyy-MM-dd")
def strTodate(stringDate: String): Either[Exception, Date] = {
try {
Right(format.parse(stringDate))
} catch {
case ioException : IOException =>
Left(ioException)
case e: Exception =>
Left(e)
}
}
def main(args: Array[String]) : Unit =
strTodate("2018-02-02") match {
case Right(date) => println(date)
case Left(err) => println(err.getMessage)
}
}
Related
I am using dd-MMM-yyyy format in String format in kotlin in android.
It returns "01-Sept-2022" as a result.
I want "01-Sep-2022" as result.
This issue shows up in android 12 & 13.
#JvmStatic
fun getCurrentDate(format: String): String {
val sdf = SimpleDateFormat(format)
val currentDate = sdf.format(Date())
return currentDate
}
How can I get my desired return value in all versions?
According to #deHaar SimpleDateFormat returns the formatted string depending on the Locale. Take a look at all locales and you will find the correct form you want. Below I added a snippet where you can easily find it. If you develop this app for the app store or for other public users you shouldn't change the Locale in SimpleDateFormat because the user in this region normally knows this format. The Locale.getDefault is also influenced by the Android system settings.
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val out = findViewById<TextView>(R.id.out)
out.text = getCurrentDate("dd-MMM-yyyy")
}
fun getCurrentDate(format: String): String {
var result = ""
val locales = listOf<Locale>(Locale.CANADA, Locale.CANADA_FRENCH, Locale.CHINA, Locale.CHINESE,
Locale.ENGLISH, Locale.FRANCE, Locale.FRENCH, Locale.GERMAN, Locale.GERMANY, Locale.ITALIAN,
Locale.ITALY, Locale.JAPAN, Locale.JAPANESE, Locale.KOREA, Locale.KOREAN, Locale.PRC,
Locale.ROOT, Locale.SIMPLIFIED_CHINESE, Locale.TAIWAN, Locale.TRADITIONAL_CHINESE, Locale.UK, Locale.US)
locales.forEach {
val sdf = SimpleDateFormat(format, it)
result += sdf.format(Date()) + "\n"
}
return result
}
returns
04-Sep.-2022
04-sept.-2022
04-9月-2022
04-9月-2022
04-Sep-2022
04-sept.-2022
04-sept.-2022
04-Sept.-2022
04-Sept.-2022
04-set-2022
04-set-2022
04-9月-2022
04-9月-2022
04-9월-2022
04-9월-2022
04-9月-2022
04-Sep-2022
04-9月-2022
04-9月-2022
04-9月-2022
04-Sep-2022
04-Sep-2022
I have succedded to format LocalDateTime to String but now how can I do the same for a list ?
The first function works but the second one doesn't work.
Here my class
class DateFormat {
companion object {
const val PATTERN = "dd-MM-yyyy HH:mm:ss"
fun format(date: LocalDateTime): String {
val formatter = DateTimeFormatter.ofPattern(PATTERN)
return date.format(formatter)
}
fun formatList(date: List<LocalDateTime>): String {
val formatter = DateTimeFormatter.ofPattern(PATTERN)
return date.forEach {
format(formatter)
}
}
}
}
to return a list of strings you could do this
fun formatList(date: List<LocalDateTime>): List<String> {
val formatter = DateTimeFormatter.ofPattern(PATTERN)
return date.map { it.format(formatter) }
}
or even shorter by referring to your other function like this:
fun formatList(date: List<LocalDateTime>): List<String> {
return date.map { format(it)}
}
or even this to make it super short
fun formatList(date: List<LocalDateTime>) = date.map { format(it)}
Edit:
realized you could even write this
fun formatList(date: List<LocalDateTime>) = date.map(::format)
Based on your second method implementation, you should return list of string instead of single result.
Also I have updated argument for first method to accept DateTimeFormatter, which will be useful while calling from second method.
class DateFormat {
companion object {
const val PATTERN = "dd-MM-yyyy HH:mm:ss"
fun format(date: LocalDateTime, formatter: DateTimeFormatter): String {
return date.format(formatter)
}
fun formatList(date: List<LocalDateTime>): List<String> {
val listResult = listOf<String>()
val formatter = DateTimeFormatter.ofPattern(PATTERN)
date.forEach {
listResult.add(format(formatter))
}
return listResult
}
}
}
You would need to join your list elements to String. How a "good format" looks like is up to you, the example below will output your dates separated by a "|" - you can use any separator you want (note: this calls your first format function):
fun formatList(date: List<LocalDateTime>): String =
date.joinToString(separator = "|") { format(it) }
EDIT: if you are on Android, note that the usage of DateTimeFormatter requires API level 26.
I have API that post and get dates:
this is the data class:
data class PlannerGet(
val date: String,
val endTime: String,
val id: Int,
val location: String,
val note: String,
val startTime: String,
val title: String
)
and i am using this library for the calendar:
https://github.com/VarunBarad/Highlightable-Calendar-View
now in the fragment i was able to highlight certain days like this:
HighlightableCalendarView.dayDecorators = listOf(
DayDecorator(
Calendar.getInstance().apply {
set(Calendar.DAY_OF_MONTH, 4)
},
Color.parseColor("#ffffff"),
Color.parseColor("#ff0000")
),
)
but i want to highlight the days from API
i tried to make it like this:
HighlightableCalendarView.dayDecorators = listOf(
DayDecorator(
Calendar.getInstance().apply {
set(PlannerGet.date)
},
Color.parseColor("#ffffff"),
Color.parseColor("#ff0000")
),
)
but i am having a problem with "set" it show "None of the following functions can be called with the arguments supplied."
i tried to add "toInt()" and still the same problem.
what is the correct way to achieve this?
This is because the params which you are passing do not match the required params.
Calendar.getInstance().apply {
set(Calendar.DAY_OF_MONTH, 4)
}
The set functions accept the int field, int value but you are passing the params as the string
PlannerGet.date
The function set
public void set(int field, int value) {
throw new RuntimeException("Stub!");
}
If you want the date to be passed from the API dates please convert the string dates to java Date object.
SOLUTION:
if (response?.body().toString() == "[]") {
}
else if (response.isSuccessful) {
response.body()?.forEach {
getplanner.add(it)
Log.e("gggg gggg",getplanner.toString())
Log.e("gggg ddddd",getplanner[0].date)
}
val list = arrayListOf<DayDecorator>()
for (dsds in getplanner) {
list.add( DayDecorator(
Calendar.getInstance().apply {
// getplanner[0].date
val input_date = dsds.date
val format1 = SimpleDateFormat("yyyy-MM-dd")
var dt1: Date? = null
dt1 = format1.parse(input_date)
val format2: DateFormat = SimpleDateFormat("dd")
val strMonth: String = format2.format(dt1)
val month = strMonth.toInt()
Log.e("dateinplanner", "" + month)
set(Calendar.DAY_OF_MONTH, month)
},
Color.parseColor("#ffffff"),
Color.parseColor("#1AB7B8")
))
}
HighlightableCalendarView.dayDecorators = list
I have a class named Child1 which I want to convert into JSON using Lift Json. Everything is working fine i was using joda date time but now i want to use Java 8 LocalDateTime but i am unable to write custom serializer for this here is my code
import org.joda.time.DateTime
import net.liftweb.json.Serialization.{ read, write }
import net.liftweb.json.DefaultFormats
import net.liftweb.json.Serializer
import net.liftweb.json.JsonAST._
import net.liftweb.json.Formats
import net.liftweb.json.TypeInfo
import net.liftweb.json.MappingException
class Child1Serializer extends Serializer[Child1] {
private val IntervalClass = classOf[Child1]
def deserialize(implicit format: Formats): PartialFunction[(TypeInfo, JValue), Child1] = {
case (TypeInfo(IntervalClass, _), json) => json match {
case JObject(
JField("str", JString(str)) :: JField("Num", JInt(num)) ::
JField("MyList", JArray(mylist)) :: (JField("myDate", JInt(mydate)) ::
JField("number", JInt(number)) ::Nil)
) => {
val c = Child1(
str, num.intValue(), mylist.map(_.values.toString.toInt), new DateTime(mydate.longValue)
)
c.number = number.intValue()
c
}
case x => throw new MappingException("Can't convert " + x + " to Interval")
}
}
def serialize(implicit format: Formats): PartialFunction[Any, JValue] = {
case x: Child1 =>
JObject(
JField("str", JString(x.str)) :: JField("Num", JInt(x.Num)) ::
JField("MyList", JArray(x.MyList.map(JInt(_)))) ::
JField("myDate", JInt(BigInt(x.myDate.getMillis))) ::
JField("number", JInt(x.number)) :: Nil
)
}
}
Object Test extends App {
case class Child1(var str:String, var Num:Int, MyList:List[Int], myDate:DateTime) {
var number: Int=555
}
val c = Child1("Mary", 5, List(1, 2), DateTime.now())
c.number = 1
println("number" + c.number)
implicit val formats = DefaultFormats + new Child1Serializer
val ser = write(c)
println("Child class converted to string" + ser)
var obj = read[Child1](ser)
println("object of Child is "+ obj)
println("str" + obj.str)
println("Num" + obj.Num)
println("MyList" + obj.MyList)
println("myDate" + obj.myDate)
println("number" + obj.number)
}
now i want to use Java 8 LocalDateTime like this
case class Child1(var str: String, var Num: Int, MyList: List[Int], val myDate: LocalDateTime = LocalDateTime.now()) {
var number: Int=555
}
what modification do i need to make in my custom serializer class Child1Serializer i tried to do it but i was unable to do it please help me
In the serializer, serialize the date like this:
def serialize(implicit format: Formats): PartialFunction[Any, JValue] = {
case x: Child1 =>
JObject(
JField("str", JString(x.str)) :: JField("Num", JInt(x.Num)) ::
JField("MyList", JArray(x.MyList.map(JInt(_)))) ::
JField("myDate", JString(x.myDate.toString)) ::
JField("number", JInt(x.number)) :: Nil
)
}
In the deserializer,
def deserialize(implicit format: Formats): PartialFunction[(TypeInfo, JValue), Child1] = {
case (TypeInfo(IntervalClass, _), json) => json match {
case JObject(
JField("str", JString(str)) :: JField("Num", JInt(num)) ::
JField("MyList", JArray(mylist)) :: (JField("myDate", JString(mydate)) ::
JField("number", JInt(number)) ::Nil)
) => {
val c = Child1(
str, num.intValue(), mylist.map(_.values.toString.toInt), LocalDateTime.parse(myDate)
)
c.number = number.intValue()
c
}
case x => throw new MappingException("Can't convert " + x + " to Interval")
}
}
The LocalDateTime object writes to an ISO format using toString and the parse factory method should be able to reconstruct the object from such a string.
You can define the LocalDateTime serializer like this.
class LocalDateTimeSerializer extends Serializer[LocalDateTime] {
private val LocalDateTimeClass = classOf[LocalDateTime]
def deserialize(implicit format: Formats): PartialFunction[(TypeInfo, JValue), LocalDateTime] = {
case (TypeInfo(LocalDateTimeClass, _), json) => json match {
case JString(dt) => LocalDateTime.parse(dt)
case x => throw new MappingException("Can't convert " + x + " to LocalDateTime")
}
}
def serialize(implicit format: Formats): PartialFunction[Any, JValue] = {
case x: LocalDateTime => JString(x.toString)
}
}
Also define your formats like this
implicit val formats = DefaultFormats + new LocalDateTimeSerializer + new FieldSerializer[Child1]
Please note the usage of FieldSerializer to serialize the non-constructor filed, number
I have tested three variation of the same code and I got it to work just fine. I want to know why the different behavior.
So I have this working code, which converts a long time stamp to a string of the ECMA date standard format :
lazy val dateFormat = new java.text.SimpleDateFormat("yyyy-MM-DD'T'HH:mm:ss.sssZ")
implicit def dateToECMAFormat(time: Long) = new {
def asECMADateString: String = {
dateFormat.format(new java.util.Date(time))
}
}
Other variation that works :
implicit def dateToECMAFormat(time: Long) = new {
val dateFormat = new java.text.SimpleDateFormat("yyyy-MM-DD'T'HH:mm:ss.sssZ")
def asECMADateString: String = {
dateFormat.format(new java.util.Date(time))
}
}
But I do not want the SimpleDateFormat to be re instanciated all the time . So I prefere the first one. But now the real mystery :
val dateFormat = new java.text.SimpleDateFormat("yyyy-MM-DD'T'HH:mm:ss.sssZ")
implicit def dateToECMAFormat(time: Long) = new {
def asECMADateString: String = {
dateFormat.format(new java.util.Date(time))
}
}
This last piece of code compiles but throws an exception at run-time; I did not manage to get the stack trace from play framework. I just know my controller in play framework 2.1 return with a 500 (Internal Server Error) without any more information (the other controllers work though and the main services are still up).
In each case the call looks like this: 100000L.asECMADateString
Can someone explain to me the different behaviors and why does the last one does not work? I though I had a good grasp of the difference between val, lazy val and def, but now I feel like I am missing something.
UPDATE
The code is called in object like this :
object MyController extends Controller{
implicit val myExecutionContext = getMyExecutionContext
lazy val dateFormat = new java.text.SimpleDateFormat("yyyy-MM-DD'T'HH:mm:ss.sssZ")
implicit def dateToECMAFormat(time: Long) = new {
def asECMADateString: String = {
dateFormat.format(new java.util.Date(time))
}
}
def myAction = Action {
Async {
future {
blocking{
//here get some result from a db
val result = getStuffFromDb
result.someLong.asECMADateString
}
} map { result => Ok(result) } recover { /* return some error code */ }
}
}
}
It is your basic playframework Async action call.
Since the difference between the 1st and 3rd examples are the lazy val, I'd be looking at exactly where your call (100000L.asECMADateString) is being made. lazy val helps correct some "order of initialization" issues with mix-ins, for example: see this recent issue to see if it's similar to yours.