1

I have a table that has country timezone range e.g.

Country: Canada Start Range: -3.5 End Range: -8.0

I have a method that pulls back the start and end range values from the table I need to convert the system time (UTC) to the country time range. If I was dealing with whole numbers it would be fine, and would just use the Calendar add regular methods that take int values but my method return doubles

I have:

private Calendar[] setCountryTime( double startRange double endRange) {
        Calendar[] clientTimeRange = null;      
        Date today = new Date(); 
        Calendar cal = Calendar.getInstance(); 
        cal.setTime(today); 

        Calendar clientStartRange = getCurrentServerTime();
            clientStartRange.add(Calendar.HOUR_OF_DAY, //what value here);
            clientStartRange.add(Calendar.MINUTE, //what value here);
        clientTimeRange[0] = clientStartRange;

        Calendar clientEndRange = getCurrentServerTime();
            clientEndRange.add(Calendar.HOUR_OF_DAY, //what value here);
            clientEndRange.add(Calendar.MINUTE, //what value here);
        clientTimeRange[1] = clientEndRange ;

        return clientTimeRange; 

    }
OneXer
  • 303
  • 9
  • 20
  • These are probably hours, so add the integer part to hours and multiply the decimal part by 60 to get the number of minutes. – Aaron May 23 '18 at 12:33
  • thanks @ Aaron, how would I deal with the minutes value as a minus? I can convert to an int but how to recognize the minus? – OneXer May 23 '18 at 12:37
  • `Calendar.add()` supports negative value (there's no `Calendar.substract()` actually), so I don't see how that's going to be a problem. With your `startRange` sample of `-3.5`the integer part is `-3` and the fractional part is `-0.5`, which is -30 minutes. – Aaron May 23 '18 at 12:47
  • thanks Aaron, a code snippet of how to do that would be nice and receive upvotes – OneXer May 23 '18 at 13:08
  • Adding or subtracting hours and minutes is the incorrect way to convert a `Calendar` to another offset from UTC. If you do insist on using the outmoded `Calendar` class (but why should you?), you need to change its `TimeZone`. – Ole V.V. May 23 '18 at 13:44

1 Answers1

0

java.time

private static final long HOURS_TO_SECONDS = TimeUnit.HOURS.toSeconds(1);

private static OffsetDateTime[] setCountryTime(double startRange, double endRange) {
    ZoneOffset startOffset = hoursToOffset(startRange);
    ZoneOffset endOffset = hoursToOffset(endRange);
    Instant now = Instant.now();
    return new OffsetDateTime[] { now.atOffset(startOffset), now.atOffset(endOffset) };
}

private static ZoneOffset hoursToOffset(double offsetHours) {
    long offsetSeconds = Math.round(offsetHours * HOURS_TO_SECONDS);
    if (offsetSeconds < ZoneOffset.MIN.getTotalSeconds() 
            || offsetSeconds > ZoneOffset.MAX.getTotalSeconds()) {
        throw new IllegalArgumentException("Offset too large " + offsetHours);
    }
    return ZoneOffset.ofTotalSeconds((int) offsetSeconds);
}

Let’s try it:

    OffsetDateTime[] canadaTimeRange = setCountryTime(-3.5, -8.0);
    System.out.println(Arrays.toString(canadaTimeRange));

Running just now this printed:

[2018-05-23T10:06:47.489234-03:30, 2018-05-23T05:36:47.489234-08:00]

Since we can instantiate a ZoneOffset from a number of seconds, the main trick is to convert your hours to seconds. The TimeUnit enum could do that for you if we had only whole hours. We can still use its conversion factor for the multiplication. It makes our intention clearer and the code less error-prone.

The Calendar class is long outdated and poorly designed. Instead I use java.time, the modern Java date and time API. It is so much nicer to work with. If you do need Calendar objects, for example for a legacy API that you cannot change, a conversion can be made.

We are still using Java 7, hence our use of Calendar

EDIT No big problem, java.time works nicely on Java 6 and 7.

  • In Java 8 and later and on newer Android devices (from API level 26, I’m told) the modern API comes built-in.
  • In Java 6 and 7 get the ThreeTen Backport, the backport of the new classes (ThreeTen for JSR 310; see the links at the bottom).
  • On (older) Android use the Android edition of ThreeTen Backport. It’s called ThreeTenABP. And make sure you import the date and time classes from org.threeten.bp with subpackages.

Links

Basil Bourque
  • 303,325
  • 100
  • 852
  • 1,154
Ole V.V.
  • 81,772
  • 15
  • 137
  • 161
  • thanks Ole V.V. , we are still using java7 , hence our use of Calendar – OneXer May 23 '18 at 13:50
  • You can use the above on Java 7 too, and since it’s a bit tricky, I would consider getting the best tool for the job (that’s no doubt `java.time`). Please see my edit. – Ole V.V. May 23 '18 at 13:52
  • from link to Oracle docs: The Date-Time package, java.time, introduced in the Java SE 8 release – OneXer May 23 '18 at 13:55
  • 1
    That agrees with what I said in the answer, but it’s only half of the truth. The package has also been backported to Java 6 and 7. – Ole V.V. May 23 '18 at 13:57
  • @OneXer See the *ThreeTen-Backport* project linked at bottom of this Answer. Add that library to your project to get most of the *java.time* functionality. Further adapted to earlier Android in the *ThreeTenABP* project also linked in Answer. Well worth the bother of adding a library as the legacy date-time classes really are an awful wretched mess. – Basil Bourque May 23 '18 at 16:27