Who is the Culprit ?
First Day at work in 2021!
Spent most of the day understanding a single line of code. This was originally written in Typescript.
return ChronoUnit.DAYS.between(Instant.ofEpochMilli(doc.${field1}.value.millis).truncatedTo(ChronoUnit.DAYS), Instant.ofEpochMilli(doc.${field2}.value.millis).truncatedTo(ChronoUnit.DAYS))
What was the issue?
For some data, the above code was returning -1
as the result.
Example:
field1: December 22nd 2020 16:00:21 PST
field2: December 23rd 2020 00:00:00 PST
The values are converted to UTC before sending to the function, so essentially we get -
field1: December 23rd 2020 00:00:21
field2: December 23rd 2020 08:00:00
Now if you check the above return statement it has truncatedTo(ChronoUnit.DAYS)
. This is to make sure that for dates like 2020-12-23 23:59:00
and 2020-12-24 00:01:00
, the difference should be 1 day (As part of requirements !)
So now, given the above 2 date values, it should return 0
as the difference value but it is returning -1
.
How did I approach and try to understand it?
When I tested this separately in Java (not in TypeScript because that language is still alien to me!)
import java.time.LocalDate;
import java.time.Month;
import java.time.temporal.ChronoUnit;
import java.time.*;
public class Example {
public static void main(String[] args) {
/* LocalDate lct = LocalDate.of(2020, 12, 24);
LocalDate rt = LocalDate.of(2020, 12, 23);
long noOfDaysBetween = ChronoUnit.DAYS.between (lct, rt);
System.out.println(noOfDaysBetween);*/
/*This is 23-12-2020 00:00:21 UTC*/
long milliseconds = 1608681621000L;
/*This is 23-12-2020 08:00:00 UTC*/
long milliseconds2 = 1608710400000L;
Instant instant = Instant.ofEpochMilli(milliseconds);
Instant instant2 = Instant.ofEpochMilli(milliseconds2);
System.out.println(instant);
System.out.println(instant2);
System.out.println("Instant: "+ instant.truncatedTo (ChronoUnit.DAYS));
System.out.println("Instant2: "+ instant2.truncatedTo (ChronoUnit.DAYS));
long res = ChronoUnit.DAYS.between (instant.truncatedTo(ChronoUnit.DAYS),instant2.truncatedTo(ChronoUnit.DAYS));
System.out.println(res);
}
}
This is giving the below output-
2020-12-23T00:00:21Z
2020-12-23T08:00:00Z
Instant: 2020-12-23T00:00:00Z
Instant2: 2020-12-23T00:00:00Z
0
So the difference I got is 0
and not -1
.
So now the only two functions I did not test out are value
and millis
-
truncatedTo(ChronoUnit.DAYS), Instant.ofEpochMilli(doc.${field2}.value.millis)
Some extra points on "Instant" class behavior:
This line of code
Instant instant = Instant.ofEpochMilli(milliseconds);
This essentially returns a date value converted to UTC. This can be confirmed by doing a small activity: Use Epoch Converter to get milli seconds for a given time in either local or UTC time
For example, take the datetime value as 23-12-2020 00:00:21
.
- For UTC Timestamp in milliseconds:
1608681621000
- For local [IST in my case]Timestamp in milliseconds:
1608661821000
Tweak the above program
long milliseconds_UTC = 1608681621000L;
long milliseconds_local = 1608661821000L;
Instant instant_UTC = Instant.ofEpochMilli(milliseconds_UTC);
Instant instant_local = Instant.ofEpochMilli(milliseconds_local);
System.out.println(instant_UTC);
System.out.println(instant_local);
The output will be -
2020-12-23T00:00:21Z
2020-12-22T18:30:21Z
As we can see,for the UTC milliseconds value the date remained the same, but for the local one i.e., IST timezone , it got changed to UTC date.
For clarification, 23-12-2020 00:00:21 IST
when converted to UTC is 2020-12-22 18:30:21
So what happened to the original issue?
I was not able to replicate the issue and it got assigned to another team who actually own it but I will keep an eye on how it is solved and update it here as Part-2
But I am glad I came across this and learnt new stuffs!