-2

I want to convert a not timezone and DST aware time to a timezone aware time, so I can convert it to UTC.

java.time atZone does not include DST, so time is one hour off.

time offset should be +2 hours and DST should be true.

import java.time.*;
import java.time.format.DateTimeFormatter;

public class test2 {
    public static void main(String[] args) {

        var formatter = DateTimeFormatter.ofPattern("yyyyMMddHHmmss");
        var dateTime = LocalDateTime.parse("20231211221101",formatter);

        ZonedDateTime ldtZoned = dateTime.atZone(ZoneId.of("Europe/Rome"));
        ZonedDateTime utcZoned = ldtZoned.withZoneSameInstant(ZoneId.of("UTC"));

        System.out.println("Has DST? "+  ldtZoned.getZone().getRules().isDaylightSavings(ldtZoned.toInstant()));

        System.out.println("notzoned time: "+ dateTime.toString());
        System.out.println("zoned time: "+ ldtZoned.toString());
        System.out.println("UTCzoned time: "+ utcZoned.toString());

    }
}

output:

 Has DST? false notzoned time: 2023-12-11T22:11:01 zoned time:
 2023-12-11T22:11:01+01:00[Europe/Rome] UTCzoned time:
 2023-12-11T21:11:01Z[UTC]

edit: Code actualy works, but datetime string is a date in december, so no DST. Change it to august and DST says true....

3
  • 1
    The DST starts at end of march and ends end of october. So move your date to a date in september and you see that DST is true
    – Jens
    Commented Jul 21, 2023 at 17:32
  • 1
    BTW: Take care of java naming conventions. Class names should start with upper case character
    – Jens
    Commented Jul 21, 2023 at 17:33
  • "offset should be +2 hours" — No, incorrect. Your premise is false. The offset planned by Rome's politicians for December 2023 is one hour ahead of UTC (+01:00), not two hours. See this reference. Commented Jul 21, 2023 at 23:27

1 Answer 1

2

java.time atZone does not include DST, so time is one hour off.

No, java.time zones do take DST into account. Your problem is different: You are asking for the time in Europe/Rome, somewhere in december, and obviously in northern hemisphere winters, daylight savings time shouldn't be applied, so java.time doesn't apply it. java.time is doing its job properly.

Possibly you are very confused and thought daylight savings ought to apply in the middle of December in Rome. In which case, the answer to your question is simple: Change nothing - java.time is already doing it right, simply adjust your erroneous expectations.

But if that's not it, I'm guessing this is your actual question:

I have a local date time (as in, a year, a month, a day, an hour, a minute, and a second value) supplied by a bad system that messed up its dates. I know that this time represents the time somewhere within the confines of what zone Europe/Rome is supposed to cover, and it is in winter, however, the bad system that messed up its dates thought for some silly reason that it was DST at the time; for example because it was set in summer and then someone added 6 months to it without taking DST into account. How do I convert this frankenstein time back into a UTC timestamp?

This certainly can be done, but we're moving away from timezones now. The concept of 'in december it is not DST' is inherent to Europe/Rome. There is no method call to go: "Yeah, this, but, as if DST applies in december".

What you have instead is an offset. The difference between a zone and an offset is that an offset never changes due to the whims of politics or the seasons - it can be represented entirely as an offset relative to UTC. In other words, '+02:00' is an offset, and evidently the one you want (as that is the offset that applies to Europe/Rome in summer). A zone, on the other hand, picks the right offset automatically based on the season and political situation (when europe decides to abolish DST entirely in, say, 2024, and Italy decides to stick with winter time permanently, then the zone would know that and use an offset of +0100 even in July 2024, but would apply an offset of +0200 in 2023).

java.time, of course, supports this: You can use OffsetDateTime and, well, apply the offset yourself.

ZoneId rome = ZoneId.of("Europe/Rome");
ZoneOffset standardOffset = rome.getRules().getStandardOffset(Instant.now());

var formatter = DateTimeFormatter.ofPattern("yyyyMMddHHmmss");
var dateTime = LocalDateTime.parse("20231211221101",formatter);

OffsetDateTime offsetted = dateTime.atOffset(standardOffset);
ZonedDateTime utced = offsetted.atZoneSameInstant(ZoneId.of("UTC"));

getStandardOffset gets you the canonical standard offset within a timezone (for the vast majority of zones out there, 'winter time' is considered the standard offset, and the summer time the 'DST variant'. Which is somewhat odd as most places have a far, far longer period where DST is applied than not, but, point is, it gets you the 'winter time'). You still have to pass an instant because politics.

The EU has already decided that all the eurozone will stop using DST entirely at some point. What has not been decided is a definitive deadline. Also, every country gets to pick its zone.

Let's say Rome decides to make summer time permanent. That wouldn't be a particularly bizarre choice - it already applies for far more of the year than winter time does.

Whatever instant in time is chosen by rome to officially transition to 'Europe/Rome means +0200 offset all the time now, instead of '+0100 in winter, +0200 in summer') - on that instant, .getStandardOffset() starts returning '+0200' instead of '+0100'. That is why that parameter is required.

1
  • You are so right, after few days struggling on this point, first with javascript, later outdated java.util. I got blindsighted, using a time string in december.... When changing it to august, it just works... Thank you for your quick and elaborate answer.
    – blablaX
    Commented Jul 22, 2023 at 10:00

Not the answer you're looking for? Browse other questions tagged or ask your own question.