Get month's start time and end time in non UTC timezone in java

I’m trying to obtain the start and end times of a specific month in a particular timezone, specifically "Asia/Kolkata" (UTC+05:30).

For instance, below are start and end times for September 2023.

Start Time: 2023-09-01 00:00:00

End Time: 2023-09-30 23:59:59

I’ve implemented the following functions in Java:

public static Long getStartTimeStampOfMonth(Month month, Year year) {
    LocalDate startDate = LocalDate.of(year.getValue(), month, 1);
    LocalDateTime startDateTime = LocalDateTime.of(startDate, LocalTime.MIN);
    ZonedDateTime istDateTime = startDateTime.atZone(ZoneId.of("Asia/Kolkata"));
    return Timestamp.valueOf(istDateTime.toLocalDateTime()).getTime();
}

public static Long getEndTimeStampOfMonth(Month month, Year year) {
    LocalDate startDate = LocalDate.of(year.getValue(), month, 1);
    LocalDate endDate = startDate.withDayOfMonth(startDate.lengthOfMonth());
    LocalDateTime endDateTime = LocalDateTime.of(endDate, LocalTime.MAX);
    ZonedDateTime istDateTime = endDateTime.atZone(ZoneId.of("Asia/Kolkata"));
    return Timestamp.valueOf(istDateTime.toLocalDateTime()).getTime();
}

However, I’ve noticed that the above code returns the start and end times based on the timezone configured on the machine. Even though I’ve explicitly specified ZoneId.of("Asia/Kolkata"), it doesn’t produce the desired results.

When I tested the code for SEPTEMBER 2023 on a machine set to the UTC timezone, I got the following output:

Start Time: 1693526400000

End Time: 1696118399999

However, I want the output to be consistent, regardless of the machine’s timezone:

Start Time: 1693506600000

End Time: 1696098599999

Please help me identify what I might be missing or suggest an alternative approach.

>Solution :

The local time zone is being introduced when you convert from ZonedDateTime to a Timestamp:

return Timestamp.valueOf(istDateTime.toLocalDateTime()).getTime();

Since you’re going through a LocalDateTime, the Timestamp.valueOf method will presume the local time zone.

From the docs:

public static Timestamp valueOf(LocalDateTime dateTime)

Obtains an
instance of Timestamp from a LocalDateTime object, with the same year, month, day of month, hours, minutes, seconds and nanos date-time value as the provided LocalDateTime.

The provided LocalDateTime is interpreted as the local date-time in the local time zone.

Instead, you can create the Timestamp from an Instant:

return Timestamp.from(istDateTime.toInstant()).getTime();

Though, since you appear to be after a long in terms of milliseconds, you could just skip the Timestamp type entirely:

return istDateTime.toInstant().toEpochMilli();

Leave a Reply