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.