I am trying to convert a date formatted in yyyy-mm-dd
to LocalDate
to milliseconds with this code.
LocalDate.parse("2022-08-01", DateTimeFormatter.ofPattern("yyyy-MM-dd"))
.atStartOfDay(ZoneId.systemDefault()).toInstant().toEpochMilli()
It returns 1659283200000
which is not correct and behind 1 day. Is there better solution for this? The expected value is 1659312000000
in UTC.
Your code is correct, if you want a count of milliseconds since the epoch reference of first moment of 1970 as seen with an offset of zero hours-minutes-seconds from UTC, 1970-01-01T00:00Z.
By the way, no need to specify a formatting pattern. Your input text complies with the ISO 8601 standard used by default in the java.time classes for parsing/generating text.
long millis =
LocalDate
.parse(
"2022-08-01"
)
.atStartOfDay(
ZoneId.systemDefault()
)
.toInstant()
.toEpochMilli()
;
I imagine the problem with getting an unexpected result is the time zone. Your results will vary by time zone.
Understand that the day starts earlier in the east. At any moment, it can be “tomorrow” in Tokyo Japan 🇯🇵 while still “yesterday” in Edmonton Alberta Canada 🇨🇦 .
(photo: NASA)
👉 To avoid surprises, specify your desired/expected time zone explicitly rather than relying on the JVM’s current default time zone.
Same date used in examples below, for two time zones and one offset.
String input = "2022-08-01" ;
ZoneId zoneIdTokyo = ZoneId.of( "Asia/Tokyo" ) ;
long millisTokyo =
LocalDate
.parse(
input
)
.atStartOfDay(
zoneIdTokyo
)
.toInstant()
.toEpochMilli()
;
ZoneId zoneIdEdmonton = ZoneId.of( "America/Edmonton" ) ;
long millisEdmonton =
LocalDate
.parse(
input
)
.atStartOfDay(
zoneIdEdmonton
)
.toInstant()
.toEpochMilli()
;
ZoneOffset offsetUtc = ZoneOffset.UTC ;
long millisUtc =
LocalDate
.parse(
input
)
.atStartOfDay(
offsetUtc
)
.toInstant()
.toEpochMilli()
;
Dump to console.
System.out.println( "Tokyo: " + millisTokyo ) ;
System.out.println( "Edmonton: " + millisEdmonton ) ;
System.out.println( "UTC: " + millisUtc ) ;
See this code run live at Ideone.com.
Tokyo: 1659279600000
Edmonton: 1659333600000
UTC: 1659312000000
You said:
The input date String should represent the current date and past 30 days which should be based on user's timezone. Example is 2022-07-08 to 2022-08-08
I suggest adding the ThreeTen-Extra library to your project. Doing so gives you access to the Interval
class to represent a span of time as a pair of Instant
objects.
Interval intervalOfPrior30DaysInUtc ( LocalDate end ) {
return
Interval
.of(
end.minusDays( 30 ).atStartOfDay( ZoneOffset.UTC ).toInstant() ,
end.atStartOfDay( ZoneOffset.UTC ).toInstant()
)
;
}