Search code examples
javatimezonejava-timetimezone-offsetdatetimeoffset

Time Zone Related Issue


I have a scenario where I have to activate/deactivate a link based on the times assigned. Here a hotel needs to activate the link 48 hours before check-in (15:00 PM) and deactivate the same 5 hours before check-in. Now the hotel can be from any part of the world. This can be managed from time-zone offset provided by the source. Ex - A particular hotel lies in Waco Texas with the offset as -2, which means 1 hour backwards from EDT time US/America. Now in my code that I have attached, the link disables one hour before than expected. As the check-in time is 3:00 PM usually the link should be disabled at 10:00 AM, however it disables as 9:00 AM.

Parameters passed to method is Check-In date and offset number received from source.

Need Assistance on how the time of 1 hour be adjusted and made correct universally for all the hotels across globe.

public static void main(String[] args) throws ParseException {
    long result = calculateTimeDifference("0","2023-07-13");
    System.out.print("Time Difference Calculated : " + result);
    if(result > 300 && result < 2880){
    System.out.println("Send Upgrade Email Active");
    }
    else {
        System.out.println("Send Upgrade Email Inactive");
    }
}

public static long calculateTimeDifference(String hotelOffset, String CheckInDt) throws ParseException {
    String CheckInTime = "15:00";

    long hoursDifference = 0;
    try {
        // Get current date and time in EDT
        ZoneId edtZoneId = ZoneId.of("America/New_York");
        LocalDateTime currentTime = LocalDateTime.now(edtZoneId);

        // Convert check-in date and time to LocalDateTime
        DateTimeFormatter dateFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");
        LocalDate checkInLocalDate = LocalDate.parse(CheckInDt, dateFormatter);
        LocalTime checkInLocalTime = LocalTime.parse(CheckInTime);

        // Convert hotel's timezone offset string to minutes
        int offsetValue = Integer.parseInt(hotelOffset);
        int offsetInMinutes = offsetValue * 30;

        // Apply the offset to get the correct zone offset
        ZoneOffset hotelZoneOffset = ZoneOffset.ofTotalSeconds(offsetInMinutes * 60);

        // Combine check-in date and time with hotel's timezone offset
        LocalDateTime checkInDateTime = LocalDateTime.of(checkInLocalDate, checkInLocalTime).atOffset(hotelZoneOffset).toLocalDateTime();

        // Calculate the time difference between current time and check-in time
        hoursDifference = ChronoUnit.MINUTES.between(currentTime, checkInDateTime);

    } catch (Exception e) {
        System.out.println("Parse Exception in calculateTimeDifference -- ");
    }
    return hoursDifference;
}

Copied from OP's comment:

The line offsetInMinutes = offsetValue * 30 has a business requirement. Let me explain it clear. Actually the Offset Value that is coming as a string, which is a calculated value coming from golden source. This is like if offset value comes as -2, then the particular hotel is running behind time of 1 hour than EST. If the value is 0, then the hotel is same as EDT time. so on

If a hotel is at offset -2, then wrt to time at New York (2023-07-16T04:30 ) then time at hotel would be 2023-07-16T03:30


Solution

  • First of all, there are a few things you must learn for your future development work:

    1. You do not need to use a DateTimeFormatter to parse a date string if it's already in ISO 8601 format which is the default format for java.time types. So, LocalDate.parse("2023-07-16") will work without requiring a DateTimeFormatter.
    2. You do not need to specify a time as a String (i.e. "15:00") and then format it; you can directly use time units e.g. LocalTime.of(15, 0).
    3. The code, LocalDateTime.of(checkInLocalDate, checkInLocalTime).atOffset(hotelZoneOffset).toLocalDateTime() is useless as it will always give you LocalDateTime.of(checkInLocalDate, checkInLocalTime) i.e. whatever you are doing with atOffset is being reverted by toLocalDateTime.
    4. For the time difference, you can use java.time.Duration which will provide you with getting different time units separately.

    Coming to your problem, all you need is to adjust the current date-time in New York with the hotelOffset, and you can do it by adding hotelOffset in minutes to it.

    Demo:

    public class Main {
        public static void main(String[] args) {
            Duration result = calculateTimeDifference("-2", "2023-07-16");
            System.out.println("Time Difference Calculated : " + result);
            // You can get time units also separately
            System.out.printf("%d hours, %d minutes%n", result.toHoursPart(), result.toMinutesPart());
        }
    
        static Duration calculateTimeDifference(String hotelOffset, String CheckInDt) {
            LocalDateTime nowInNY = LocalDateTime.now(ZoneId.of("America/New_York"));
    
            // Convert hotel's timezone offset string to minutes
            int offsetValue = Integer.parseInt(hotelOffset);
            int offsetInMinutes = offsetValue * 30;
    
            LocalDateTime nowAtHotel = nowInNY.plusMinutes(offsetInMinutes);
    
            LocalDateTime checkInDateTime = LocalDate.parse(CheckInDt)
                                                .atTime(LocalTime.of(15, 0));
    
            return Duration.between(nowAtHotel, checkInDateTime);
        }
    }
    

    Output from a sample run:

    Time Difference Calculated : PT50M51.207969S
    0 hours, 46 minutes
    

    ONLINE DEMO

    Learn more about the modern Date-Time API from Trail: Date Time.