I was comparing two dates which seem to be equal, but they contain a different name of zones: one is Etc/UTC, another is UTC. 
According to this question: Is there a difference between the UTC and Etc/UTC time zones? - this two zones are the same. But my tests fail:
import org.junit.Test;
import java.sql.Timestamp;
import java.time.ZoneId;
import java.time.ZonedDateTime;
import static org.junit.Assert.assertEquals;
public class TestZoneDateTime {
    @Test
    public void compareEtcUtcWithUtc() {
        ZonedDateTime now = ZonedDateTime.now();
        ZonedDateTime zoneDateTimeEtcUtc = now.withZoneSameInstant(ZoneId.of("Etc/UTC"));
        ZonedDateTime zoneDateTimeUtc = now.withZoneSameInstant(ZoneId.of("UTC"));
        // This is okay
        assertEquals(Timestamp.from(zoneDateTimeEtcUtc.toInstant()), Timestamp.from(zoneDateTimeUtc.toInstant()));
        // This one fails
        assertEquals(zoneDateTimeEtcUtc,zoneDateTimeUtc);
        // This fails as well (of course previous line should be commented!)
        assertEquals(0, zoneDateTimeEtcUtc.compareTo(zoneDateTimeUtc));
    }
}
The result:
java.lang.AssertionError: 
Expected :2018-01-26T13:55:57.087Z[Etc/UTC]
Actual   :2018-01-26T13:55:57.087Z[UTC]
More specifically, I would expect, that ZoneId.of("UTC") would be equal to ZoneId.of("Etc/UTC"), but they aren't!
As @NicolasHenneaux suggested, I should probably use compareTo(...) method. That's good idea, but zoneDateTimeEtcUtc.compareTo(zoneDateTimeUtc) returns -16 value, because of this implementation inside ZoneDateTime:
cmp = getZone().getId().compareTo(other.getZone().getId());
Assertion result:
java.lang.AssertionError: 
Expected :0
Actual   :-16
So the problem lies somewhere in ZoneId implementation. But I still would expect that if both zone ids are valid and both designate the same zone, then they should be equal.
My question is: is it a library bug, or I am doing something wrong?
UPDATE
Several people tried to convince me that it is a normal behaviour, and it is normal that the implementation of comparison methods uses String id representation of the ZoneId. In this case I should ask, why does the following test runs okay? 
    @Test
    public void compareUtc0WithUtc() {
        ZonedDateTime now = ZonedDateTime.now();
        ZoneId utcZone = ZoneId.of("UTC");
        ZonedDateTime zonedDateTimeUtc = now.withZoneSameInstant(utcZone);
        ZoneId utc0Zone = ZoneId.of("UTC+0");
        ZonedDateTime zonedDateTimeUtc0 = now.withZoneSameInstant(utc0Zone);
        // This is okay
        assertEquals(Timestamp.from(zonedDateTimeUtc.toInstant()), Timestamp.from(zonedDateTimeUtc0.toInstant()));
        assertEquals(0, zonedDateTimeUtc.compareTo(zonedDateTimeUtc0));
        assertEquals(zonedDateTimeUtc,zonedDateTimeUtc0);
    }
If Etc/UTC is the same as UTC, then I see two options:
- compareTo/equals method shouldn't use ZoneId id, but should compare their rules
 Zone.of(...)is broken and should treatEtc/UTCandUTCas the same time zones.
Otherwise I don't see why UTC+0 and UTC work fine.
UPDATE-2 I have reported a bug, ID : 9052414. Will see what Oracle team will decide.
UPDATE-3 The bug report accepted (don't know will they close it as "won't fix" or not): https://bugs.openjdk.java.net/browse/JDK-8196398