How to get day of the week of GMT using kotlin? - kotlin

For EXAMPLE, current UTC time is:
17:14:24 UTC
Friday, 5 November 2021
I want to get the result "6" (Sunday = 1 => Friday = 6)

Using kotlinx.datetime (which is multiplatform):
import kotlinx.datetime.DayOfWeek
import kotlinx.datetime.Instant
import kotlinx.datetime.TimeZone
import kotlinx.datetime.isoDayNumber
import kotlinx.datetime.toLocalDateTime
public val DayOfWeek.dayNumberStartingFromSunday: Int
get() = when (this) {
DayOfWeek.SUNDAY -> 1
else -> isoDayNumber + 1
}
fun main() {
// val now: Instant = Clock.System.now()
val now = Instant.parse("2021-11-05T17:14:24Z")
val datetimeInUtc = now.toLocalDateTime(TimeZone.UTC)
val dayNumberStartingFromSunday = datetimeInUtc.dayOfWeek.dayNumberStartingFromSunday
println(dayNumberStartingFromSunday) // 6
}

The first day of the week is Locale specific. Since you want the first day of the week to be Sunday, you can use Locale.US.
Demo:
import java.time.LocalDateTime;
import java.time.temporal.ChronoUnit;
import java.time.temporal.TemporalAdjusters;
import java.time.temporal.WeekFields;
import java.util.Locale;
public class Main {
public static void main(String[] args) {
// Test
System.out.println(getDayOfWeekValue(LocalDateTime.of(2021, 11, 5, 17, 14, 24)));
}
static int getDayOfWeekValue(LocalDateTime input) {
return Math.toIntExact(
ChronoUnit.DAYS.between(
input.with(
TemporalAdjusters.previousOrSame(
WeekFields.of(Locale.US)
.getFirstDayOfWeek())),
input.plusDays(1)));
// Note: One day has been added as ChronoUnit.DAYS.between excludes
// the second parameter while calculating the number of days
}
}
Output:
6
ONLINE DEMO
Note: Test this code with Locale.UK (for which the first day of the week is Monday) and you will get 5 as the output. As per your requirement, you can change the definition of the function like
static int getDayOfWeekValue(LocalDateTime input, Locale locale) {
return Math.toIntExact(
ChronoUnit.DAYS.between(
input.with(
TemporalAdjusters.previousOrSame(
WeekFields.of(locale)
.getFirstDayOfWeek())),
input.plusDays(1)));
// Note: One day has been added as ChronoUnit.DAYS.between excludes
// the second parameter while calculating the number of days
}
Learn more about the modern Date-Time API* from Trail: Date Time.
* If you are working for an Android project and your Android API level is still not compliant with Java-8, check Java 8+ APIs available through desugaring. Note that Android 8.0 Oreo already provides support for java.time. Check this answer and this answer to learn how to use java.time API with JDBC.

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

Siebel Business(E-script) Service Calculate Expiry Date

I have a requirement to create a business service function to calculate expiry date , 2 weeks from a date field in Siebel.
I have written the code in Java which is
public static Date checkexpiry(Date Datefield)
{
Calendar cal = Calendar.getInstance();
cal.setTime(Datefield);
cal.add(Calendar.DATE, -14);
Date twoWeeksToExpiry = cal.getTime();
System.out.println(twoWeeksToExpiry);
return twoWeeksToExpiry;
}
if current date is equal to twoWeeksToExpiry {do .....}
So how can I re-write this code on Siebel using a business service particularly E-script.
The whole idea is have an output Yes is its 2 weeks before a date field in Siebel.
This will later be used in a work flow.
OK so have started Migrating my Java coding skills to Siebel E-Script I came up with this.
function ExpiryNotification(Inputs,Outputs)
{
try
{
var expiryDate = Inputs.GetProperty("DateField");
var eDate= new Date(expiryDate);
var notificationdate = eDate-14;
var currentdate = Today();
if (currentdate==notificationdate){
Outputs.SetProperty("Notification", "Y")
}
else {
Outputs.SetProperty("Notification", "N")
}
catch(e)
{
TheApplication().RaiseErrorText(e.toString());
}
}
However I did not use the Business Service ..I used a calculated field on my Business Component.
The calculated Fields
1 twoWeeksToExpiry = Datefield-14
Notification = IIf (Today()==[twoWeeksToExpiry], "Y", "N")
So this solved the problem without scripting,
Will appreciate any suggestions on my scripting thou I didn't use it.