0

My client is sitting in other Zone. On UI there is way to search by DateRange (start and end date). Client sends start and end date in String form. eg -> startDate = "DD/MM/YYYY", endDate = "DD/MM/YYYY". Server converts dates to searchStartDate = "DD/MM/YYYY 00:00:01" and searchEndDate = "DD/MM/YYYY 23:59:59". But before searching in DB I need to add "zone time difference" in these searchStartDate and searchEndDate. Different clients are sitting in different zones. How do we add/subtract the zone diff time using java 8 APIs?

eg - my server is running in UTC. and Client sitting in IST. I will subtract 5H:30M from both searchStartDate and searchEndDate before searching into DB.

What I have - LocalDateTime searchStartDate and searchEndDate. What I want searchStartDate = searchStartDate.plus(<UtcIstTimeZoneDiff>).

Edit - Server knows the timeZone of every client.

doga
  • 471
  • 2
  • 9
  • 20
  • So you want to allow the users to search using their local timezone, meaning you need to have the UI be timezone aware? – Kayaman Feb 20 '18 at 14:10
  • UI is converting time in its LocalTime. So client running in IST timezone will convert time to IST. Actually DTOs contain UTC time only. Only for searching I need to adjust search times based on client zone. – doga Feb 20 '18 at 14:14
  • @Kayaman I have updated question. Please have a look. – doga Feb 20 '18 at 14:19
  • 2
    How well have you searched? Similar questions have been asked more than once, so I recommend, don’t wait for an answer here, go out and find a good one that is already out there. – Ole V.V. Feb 20 '18 at 14:25
  • I want to solve it with Java 8 API. There are answers using java.util.TimeZone API. – doga Feb 20 '18 at 14:27
  • 1
    Possible duplicate of [Convert Date/Time for given Timezone - java](https://stackoverflow.com/questions/7670355/convert-date-time-for-given-timezone-java). Solving with Java 8 is also what I recommend. See [this answer](https://stackoverflow.com/a/39300461/5772882). – Ole V.V. Feb 20 '18 at 14:27
  • 1
    Possible duplicate of [Java 8 timezone conversion](https://stackoverflow.com/questions/45611479/java-8-timezone-conversion). And/or possibly even more of [Java 8 timezone conversions](https://stackoverflow.com/questions/25885591/java-8-timezone-conversions). – Ole V.V. Feb 20 '18 at 14:37
  • Are you sure you even need a timezone conversion? What is the column type in your database of the date or timestamp column on which you’ll be basing your search? – VGR Feb 20 '18 at 16:29
  • I am storing data into MongoDB. And then fetching data on client request based on search filter. Client request contains date strings as I mentioned in question. I need to provide data to client as per their timezone. So I need to query data by shifting search time by "time zone diff" time and provide data as per that time duration. Please read my edit in question. – doga Feb 20 '18 at 17:00

2 Answers2

3
    DateTimeFormatter searchDateFormatter = DateTimeFormatter.ofPattern("dd/MM/uuuu");
    ZoneId clientZone = ZoneId.of("Asia/Colombo");
    String startDate = "29/01/2018";
    String endDate = "04/02/2018";

    Instant searchStartTime = LocalDate.parse(startDate, searchDateFormatter)
            .atStartOfDay(clientZone)
            .toInstant();
    Instant searchEndTime = LocalDate.parse(endDate, searchDateFormatter)
            .plusDays(1)
            .atStartOfDay(clientZone)
            .toInstant();

    System.out.println("" + searchStartTime + " inclusive to " 
                        + searchEndTime + " exclusive");

This example prints

2018-01-28T18:30:00Z inclusive to 2018-02-04T18:30:00Z exclusive

Use a half-open interval: Instead of trying to decide the last clock hour in a day and consider whether you want how many decimals on the seconds, it’s better to set the search end time to the first moment of the following day and then just only retrieve records that come strictly before that time.

I am giving you start and end times as Instants. Most JDBC drivers are happy to use them, and I consider it an advantage that they inherently represent points on the timeline, which is what you need them for. If for your search you do need LocalDateTime, here’s a way to obtain one:

    LocalDateTime searchStartTime = LocalDate.parse(startDate, searchDateFormatter)
            .atStartOfDay(clientZone)
            .toOffsetDateTime()
            .withOffsetSameInstant(ZoneOffset.UTC)
            .toLocalDateTime();

The search end time case is similar.

Ole V.V.
  • 81,772
  • 15
  • 137
  • 161
0

There's not much to do since you are already storing all date/time entries in UTC, and you know the client's time zone. All you need to do is convert UTC date/time to/from the client's time zone. Use ZonedDateTime.withZoneSameInstant() for that:

Returns a copy of this date-time with a different time-zone, retaining the instant. This method changes the time-zone and retains the instant. This normally results in a change to the local date-time.

Here's some sample code for converting from UTC to IST:

public class Main {

    public static void main(String[] args) {

        // Get some arbitrary UTC value for the search start date (regardless of caller's time zone).
        // Note that the zone ID for UTC is "Z".
        ZonedDateTime utcSearchStartDate = ZonedDateTime.now(ZoneOffset.UTC);

        // Convert the UTC date/time to the target time zone.
        ZoneId clientZone = Main.getClientZoneId();
        ZonedDateTime adjustedSearchStartDate = utcSearchStartDate.withZoneSameInstant(clientZone);

        System.out.println("Current date/time for " + utcSearchStartDate.getZone().getId() +  " = " + utcSearchStartDate.format(DateTimeFormatter.ofPattern("yyyy-MM-dd hh:mm:ss")));
        System.out.println("Current date/time for " + adjustedSearchStartDate.getZone().getId() +  " = " + adjustedSearchStartDate.format(DateTimeFormatter.ofPattern("yyyy-MM-dd hh:mm:ss")));
    }

    // Your logic to get the actual ZoneID of the client goes in this method.
    static ZoneId getClientZoneId() {

        return ZoneId.of("Asia/Kolkata"); // For example...
    }
}

The output from running that code is shown below, where the date/time for IST has been adjusted by +5:30:

Current date/time for Z = 2018-02-21 06:09:19
Current date/time for Asia/Kolkata = 2018-02-21 11:39:19
skomisa
  • 16,436
  • 7
  • 61
  • 102