Kotlin SimpleDateFormat parse wrong timezone - kotlin

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

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

js-joda convert UTC zoned datetime into local datetime

I'm struggling to convert between a parsed UTC datetime into a LocalDateTime (America/New_York), with the hours adjusted accordingly between the two timezones, using the js-joda library.
In the javascript native Date object, what's stored is in UTC and is adjusted for the local (system) timezone at the time of display (.toString(), etc). I understand js-joda works differently, so I am assuming it's my own misunderstanding of just how js-joda timezones work. Regardless, I can't seem to get any kind of DateTime to report/show that it's 8am in the morning in New York, given a UTC time of 12pm noon.
Below is the Jest test-code to show what's been attempted so far.
import {
DateTimeParseException,
LocalDateTime,
ZonedDateTime, ZoneId,
} from '#js-joda/core';
import '#js-joda/timezone';
// (Jest tests)
test('converting a utc zoned-datetime into a local datetime', () => {
expect(ZoneId.systemDefault().id().toString()).toMatch('America/New_York');
// America/New_York is currently -04:00 from UTC (daylight savings on)
const utcStr1 = "2022-09-27T12:00:00Z";
const utcStr2 = "2022-09-27T12:00:00+00:00";
const utcDT = ZonedDateTime.parse(utcStr1);
// make sure I understand how parsing UTC forms work:
expect(utcDT).toEqual(ZonedDateTime.parse(utcStr2)); // OK
expect(utcDT.zone().id()).toEqual(ZoneId.UTC.id()); // OK
// trying to parse a UTC datetime string using LocalDateTime fails,
// so that won't work...
expect(() => LocalDateTime.parse("2022-09-27T12:00:00Z")).toThrow(DateTimeParseException);
expect(() => LocalDateTime.parse("2022-09-27T12:00:00+00:00")).toThrow(DateTimeParseException);
/*
How do I convert this UTC datetime into a LocalDateTime, adjusting for UTC (hr:12) -> America/New_York (hr:8)?
All of the below attempts fail, returning 12.
*/
expect(utcDT.toOffsetDateTime().hour()).toEqual(8); // FAILS: .hour() returns 12 not 8
expect(utcDT.toLocalDateTime().hour()).toEqual(8); // FAILS: .hour() returns 12 not 8
expect(utcDT.withZoneSameLocal(ZoneId.systemDefault()).hour()).toEqual(8); // FAILS: .hour() returns 12 not 8
});
The function to use is withZoneSameInstant:
const localDateTime = utcDT.withZoneSameInstant(ZoneId.systemDefault());

Jackson date serialization XMLGregorianCalendar incorrectly when time is undefined

Currently I am trying to serialize the XMLGregorianCalendar with jackson XML to 2 different formats. One completely filled with date, time and timezone and one filled with only the date. The first one now works correctly and I will just get 2022-03-23T15:30:00.000+00:00 back. Only the second one which should only return the date gives back 2022-03-22T23:00:00.000+00:00 instead of 2022-03-23. I know that you can most likely change it inside the setDateFormat in the jackson config but am not sure how the configuration should look like. Currently the code that I have looks like this:
Jackson config:
val objectMapperXml: ObjectMapper = XmlMapper().apply {
enable(ToXmlGenerator.Feature.WRITE_XML_DECLARATION)
setAnnotationIntrospector(
AnnotationIntrospector.pair(
JakartaXmlBindAnnotationIntrospector(TypeFactory.defaultInstance()),
JacksonXmlAnnotationIntrospector(false)
)
)
disable(DeserializationFeature.ADJUST_DATES_TO_CONTEXT_TIME_ZONE)
disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS)
disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES)
setSerializationInclusion(JsonInclude.Include.NON_EMPTY)
}
XMLGregorianCalendar for the dateonly extension:
val ZonedDateTime.toXMLGregorianCalenderDaysOnly: XMLGregorianCalendar
get() {
val cal = GregorianCalendar.from(this)
return DatatypeFactory.newInstance().newXMLGregorianCalendar(cal).apply {
hour = DatatypeConstants.FIELD_UNDEFINED
minute = DatatypeConstants.FIELD_UNDEFINED
second = DatatypeConstants.FIELD_UNDEFINED
millisecond = DatatypeConstants.FIELD_UNDEFINED
timezone = DatatypeConstants.FIELD_UNDEFINED
}
}
For the XMLGregorianCalendar I put all the values that I don't want to see as UNDEFINED. How can I solve this serialization issue with jackson XML?

Compare ISO time in JMETER assertion

I am reading the measurements and I have 2 ISO time stamps.
Now using the JSON extractor, I have parsed the time into 2 variables namely "time1" and "time2"
Now I want to compare the time and decide which one is greater.
Sample time that I had parsed to the variables are like below,
time1: 2021-07-01T00:00:03Z
time2: 2021-07-01T00:00:02Z
Now I want to compare and print the value saying time1 is greater than time2 and the returned response is in descending order.
I tried the below snippet in JSR223:
String time1 = vars.get("time1");
String time2 = vars.get("time2");
OffsetDateTime created = OffsetDateTime.parse(time1);
OffsetDateTime updated = OffsetDateTime.parse(time2);
if (updated.isAfter(created)) {
System.out.println("PASSED");
} else {
System.out.println("FAILED");
}
Working example with import and using log.info
import java.time.OffsetDateTime;
String time1 = vars.get("time1");
String time2 = vars.get("time2");
OffsetDateTime created = OffsetDateTime.parse(time1);
OffsetDateTime updated = OffsetDateTime.parse(time2);
if (updated.isAfter(created)) {
log.info("PASSED");
} else {
log.info("FAILED");
}

Convert string into LocalDate 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