0

I have a Date with the actual time of my system (I live in Spain). I need to change it to UTC-1, but it doesn't matter if I write "UTC-1" or "UTC-2", it always gives me the same time less 2 hours, I mean:

My system hour (time_utc): 11:00 13/04/2021 Try UTC-1 (time): 09:00 13/04/21 Try UTC-2 (time): 09:00 13/04/21

I have this code:

    Date time_utc = new Date();
    DateFormat convertidor = new SimpleDateFormat("yyyy-MM-dd HH:00:00.000");    
    
    convertidor.setTimeZone(TimeZone.getTimeZone("UTC-1"));     

    time = convertidor.format(time_utc);    

Why it doesn't work? Can anyone helps me? Thanks a lot!

Imrik
  • 674
  • 2
  • 14
  • 32
  • 1
    That's one of the reasons for the existence of `java.time`... Do you have to use a `java.util.Date` or could you switch to a modern class, let's say `java.time.OffsetDateTime`? – deHaar Apr 13 '21 at 09:47
  • Try writing `UTC-01:00` – Siberio Apr 13 '21 at 09:49
  • @Siberio it doesn't work – Imrik Apr 13 '21 at 09:54
  • @deHaar how can I do with OffsetDateTime? – Imrik Apr 13 '21 at 09:54
  • Just answered... – deHaar Apr 13 '21 at 09:59
  • 1
    @Imrik - Do you actually need a [time zone for a specific location](https://en.wikipedia.org/wiki/List_of_tz_database_time_zones)? (For example, Spain is `Europe/Madrid`.) – Matt Johnson-Pint Apr 13 '21 at 13:37
  • I recommend you don’t use `Date`, `DateFormat`, `SimpleDateFormat` and `TimeZone`. Those classes are poorly designed and long outdated. Instead use `ZonedDateTime`, `ZoneId` and `DateTimeFormatter`, all from [java.time, the modern Java date and time API](https://docs.oracle.com/javase/tutorial/datetime/). – Ole V.V. Apr 14 '21 at 03:46
  • Related: [Java: getTimeZone without returning a default value](https://stackoverflow.com/questions/33373442/java-gettimezone-without-returning-a-default-value) and [Strange Java Timezone Date Conversion Problem](https://stackoverflow.com/questions/7041267/strange-java-timezone-date-conversion-problem). – Ole V.V. Apr 14 '21 at 03:59

2 Answers2

2

¡Hola!

You can do that in a pretty short way using java.time (if you are allowed and willing to do so).

There are special classes that represent a moment in time in different time zones of offsets. One of them is an OffsetDateTime, see this example:

public class Main {

    public static void main(String[] args) {
        // create one of your example date times in UTC
        OffsetDateTime utcOdt = OffsetDateTime.of(2021, 4, 13, 11, 0, 0, 0, ZoneOffset.UTC);
        // and print it
        System.out.println(utcOdt);
        /*
         * then create another OffsetDateTime 
         * representing the very same instant in a different offset
         */
        OffsetDateTime utcPlusTwoOdt = utcOdt.withOffsetSameInstant(ZoneOffset.ofHours(2));
        // and print it
        System.out.println(utcPlusTwoOdt);
        // do that again to see "the other side" of UTC (minus one hour)
        OffsetDateTime utcMinusOneOdt = utcOdt.withOffsetSameInstant(ZoneOffset.ofHours(-1));
        // and print that, too.
        System.out.println(utcMinusOneOdt);
    }
}

It outputs the following three lines:

2021-04-13T11:00Z
2021-04-13T13:00+02:00
2021-04-13T10:00-01:00

As you can see, the time of day is adjusted according to the offset.

The output could be formatted in your desired style if needed (this currently just uses the toString() method of OffsetDateTime).

UPDATE

You can achieve the output formatted as desired by defining the pattern as uuuu-MM-dd HH:mm when using a java.time.format.DateTimeFormatter.
Just add the following lines to the example above:

DateTimeFormatter dtf = DateTimeFormatter.ofPattern("uuuu-MM-dd HH:mm");

System.out.println(utcOdt.format(dtf));
System.out.println(utcPlusTwoOdt.format(dtf));
System.out.println(utcMinusOneOdt.format(dtf));

This would then output

2021-04-13 11:00
2021-04-13 13:00
2021-04-13 10:00

And if you really want fix zeros for seconds and millis, then create your DateTimeFormatter like this:

DateTimeFormatter dtf = DateTimeFormatter.ofPattern("uuuu-MM-dd HH:mm:00.000");

which will cause output like this:

2021-04-13 11:00:00.000
2021-04-13 13:00:00.000
2021-04-13 10:00:00.000
deHaar
  • 17,687
  • 10
  • 38
  • 51
  • I can try, thanks! how can i do to get this format? "2021-04-13 10:00:00.000" – Imrik Apr 13 '21 at 10:02
  • I mean, without the +02:00 and the secs and millisecs? – Imrik Apr 13 '21 at 10:02
  • @Imrik see the last update of my answer, too, please... – deHaar Apr 13 '21 at 10:14
  • I have a problem, I cannot use the class you say :( – Imrik Apr 13 '21 at 10:32
  • and I try with this: TimeZone.getTimeZone("Africa/Cabo Verde") that has 3 hours less than here in Spain, and it only take 2 hours less, also with "America/Greenland"... why? – Imrik Apr 13 '21 at 10:33
  • @Imrik why can't you use that class? Are you using a Java version below 8? – deHaar Apr 13 '21 at 10:34
  • the client don't let us to use it – Imrik Apr 13 '21 at 10:36
  • 1
    @Imrik that's sad, it's the far better option, [read here why...](https://codeblog.jonskeet.uk/2017/04/23/all-about-java-util-date/) For the old and troublesome classes, have a look around for old questions with similar topics. There's a lot of them on stackoverflow, e.g. [this one](https://stackoverflow.com/questions/39557374/how-to-set-offset-of-a-java-util-date). – deHaar Apr 13 '21 at 12:09
  • 1
    Beautiful answer. Gracias, danke schön. – Ole V.V. Apr 14 '21 at 03:41
  • There are no suce time zones as Africa/Cabo_Verde and America/Grenland (just as there is no such time zone as UTC-1). Try Atlantic/Cape_Verde (names are always in English) and America/Nuuk (time zones are names after largest city or populated area when one exists). – Ole V.V. Apr 14 '21 at 03:52
  • (Also Greenland consists of more than one time zone.) – Ole V.V. Apr 14 '21 at 04:02
1

As a supplement to the good answer by deHaar:

  1. As Matt Johnson-Pint already asked, do you need to convert to a different time zone? This would be the most typical. If so, use that time zone, not just a UTC offset of -1. By all probability that time zone has used other offsets in the past and may well do so in the future. So -01:00 isn’t safe. A real time zone ID like Atlantic/Cape_Verde is safer.
  2. You don’t need to go through the current time in your own time zone and convert. java.time can directly give you the current time in another time zone or at a specific UTC offset.
  3. java.time can also truncate a time to whole hours.

So for example:

    DateTimeFormatter formatter
            = DateTimeFormatter.ofPattern("uuuu-MM-dd HH:mm:ss.SSS");
    
    ZoneId zone = ZoneId.of("Atlantic/Cape_Verde");
    ZonedDateTime nowInCaboVerde = ZonedDateTime.now(zone);
    
    System.out.println(nowInCaboVerde);
    System.out.println(nowInCaboVerde.truncatedTo(ChronoUnit.HOURS)
            .format(formatter));

Output:

2021-04-14T03:12:28.272010-01:00[Atlantic/Cape_Verde]
2021-04-14 03:00:00.000

PS Cabo Verde/Cape Verde was at offset -02:00 until 1975.

What went wrong in your code?

This is how confusingly the old TimeZone class behaves and one of the reasons why you should never use it: When given a time zone ID that it does not recognize, it returns GMT and pretends all is well. UTC-1 is not a recognized time zone ID. In case it didn’t make sense to refer to a real time zone and you needed the offset -01:00 from UTC, you might have used GMT-1 or GMT-01:00. Yes, TimeZone refers to UTC as GMT even though they are not strictly speaking the same.

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