I am having an exceedingly hard time trying to figure out what seems to be a simple problem.
I would like to calculate the difference (offset?) in milliseconds between the UTC instant and the JVM instant (i.e. specific to the machine running the code).
I have tried the following initializations (sorry, this is in Kotlin, not Java):
// 1
val difference = TimeZone.getDefault().getOffset(System.currentTimeMillis())
// 2
val difference = ZoneId.systemDefault().rules.getOffset(Instant.EPOCH).totalSeconds * 1000
// 3
val difference = ZonedDateTime.now(ZoneId.systemDefault()).offset.totalSeconds * 1000
To be more specific: I am running this on my Mac on the US west coast today (Feb 22, 2024 -- i.e. during Daylight Savings). All 3 initializations produce -28800000
(i.e. timezone-based) when I am looking for an initialization that will produce -25200000
(i.e. DST-sensitive / instant-based).
What am I doing wrong here?
I would like the solution to be timezone/machine agnostic (i.e. I could run this code on any machine around the world without any specific input like a string timezone).
EDIT:
As @Louis Wasserman pointed out, my expectation that the initializations would produce -25200000
is incorrect as the current time difference is in fact -28800000
.
My incorrect expectation is due to the fact I had written the following test:
@Test
fun timeStrToEpochMillis_invariantValidation_happyPaths() {
// Arrange
val testTimeStr = "2023-06-13 20:21:46"
// Act
val result = timeStrToEpochMillis(testTimeStr)
// Assert
assertEquals(1686687706000, result)
}
For the below function:
fun timeStrToEpochMillis(timeStr: String): Long {
val df = SimpleDateFormat("yyyy-MM-dd HH:mm:ss")
return df.parse(timeStr).time
}
When I ran the above test in a container, whose default time zone is UTC, the test would pass. However, when running the above test on my local machine, whose default time zone is Pacific, the test would fail.
I overlooked that the difference ought to be based on the test string, like so:
@Test
fun timeStrToEpochMillis_invariantValidation_happyPaths() {
// Arrange
val testTimeStr = "2023-06-13 20:21:46"
// Act
val result = timeStrToEpochMillis(testTimeStr)
val diff = TimeZone.getDefault().getOffset(result)
// Assert
assertEquals(1686687706000 + diff, result)
}
Thanks again to @Louis Wasserman for pointing out the obvious.
It is not currently Daylight Savings Time on the US West Coast. The time zone America/Los_Angeles, used by the US West Coast, is currently 28800000 milliseconds from UTC.
The JVM is correct here.
You later commented:
My question is missing some context: I am trying to apply this logic to a specific date time string ("2023-06-13 20:21:46"), which is in Daylight Savings
You have found ZonedDateTime.now(ZoneId.systemDefault()).offset)
: use instead ZonedDateTime.of(LocalDateTime, ZoneId)
, with that LocalDateTime
.