如何找到与给定的 LocalDateTime 和 ZoneId 对应的所有 Instants?

How to find all Instants which correspond to the given LocalDateTime and ZoneId?

在将Instant转换为LocalDateTime时,可能会出现几个不同的Instant转换为相同的LocalDateTime的情况。例如。在有夏令时的时区。

我的问题是是否可以编写一个适用于任何 ZoneIdLocalDateTime 以及 returns 所有 Instant 在给定时间内的通用函数映射到给定 LocalDateTime:

的区域
List<Instant> localToInstants(LocalDateTime dt, ZoneId zone)

对于任何给定的一对 LocalDateTimeZoneId,只有一个 Instant - 因为 Instant 是 UTC 偏移量的时刻,+0:0 .

您可能正在寻找从 LocalDateTimeList<OffsetDateTime> 的转换,其编码如下:

List<OffsetDateTime> localToOffsets(LocalDateTime ldt, ZoneId zone) {
    ZoneRules rules = zone.getRules();

    return rules.getValidOffsets(ldt).stream()
        .map(ldt::atOffset)
        .collect(Collectors.toList());
}

循环所有时区,将每个时区指定为您的 LocalDateTime. From each ZonedDateTime object produced you can extract an Instant 的上下文。其中一些 Instant 对象将代表同一时刻,其中各个时区碰巧在该日期和时间共享相同的距 UTC 的偏移量。

在此示例代码中,我们从特定的 LocalDateTime 开始。这意味着日期带有一天中的时间——在没有时区或与 UTC 的偏移量的情况下本质上是模棱两可的。我们将 LocalDateTime 重复放置在这样的上下文中,放置在 ZonedDateTime 对象的 tzdata within our version of Java. The result of placing LocalDateTime in a ZoneId is a ZonedDateTime. We then extract an Instant, effectively adjusting to UTC as Instant is a moment as seen in UTC. We put the Instant object into a Map as the key. For the value of the map, we have a collection of ZonedDateTime objects that report that same instant. So we have a multimap, a map of key Instant to multiple values, a Set 已知的每个时区中。

LocalDateTime myLocalDateTime = LocalDateTime.of( 2021 , Month.MARCH , 23 , 15 , 30 , 0 , 0 );
Set < String > zoneNames = ZoneId.getAvailableZoneIds();
NavigableMap < Instant, NavigableSet < ZonedDateTime > > instantToZdts = new TreeMap <>();
for ( String zoneName : zoneNames )
{
    ZoneId z = ZoneId.of( zoneName );
    ZonedDateTime zdt = myLocalDateTime.atZone( z );
    Instant instant = zdt.toInstant();
    //System.out.println( myLocalDateTime + " in " + z + " is " + zdt + " = " + instant );

    instantToZdts.putIfAbsent( instant , new TreeSet <>() );
    instantToZdts.get( instant ).add( zdt );
}

向控制台报告结果。

System.out.println( "instantToZdts = " + instantToZdts );
System.out.println( "---------------|  " + myLocalDateTime + "  |-----------------------" );
System.out.println( "" ) ;
for ( Instant instant : instantToZdts.keySet() )
{
    Set < ZoneId > zoneIds = instantToZdts.get( instant ).stream().map( zonedDateTime -> zonedDateTime.getZone() ).collect( Collectors.toSet() );
    System.out.println( "Instant: " + instant + " in: " + zoneIds );
    System.out.println( "" );
}

当运行.

---------------|  2021-03-23T15:30  |-----------------------

Instant: 2021-03-23T01:30:00Z in: [Pacific/Apia, Pacific/Kiritimati, Etc/GMT-14]

Instant: 2021-03-23T01:45:00Z in: [Pacific/Chatham, NZ-CHAT]

Instant: 2021-03-23T02:30:00Z in: [Antarctica/McMurdo, Pacific/Tongatapu, Pacific/Enderbury, Pacific/Fakaofo, NZ, Antarctica/South_Pole, Pacific/Auckland, Etc/GMT-13]

Instant: 2021-03-23T03:30:00Z in: [Pacific/Funafuti, Pacific/Norfolk, Etc/GMT-12, Asia/Kamchatka, Pacific/Tarawa, Kwajalein, Pacific/Kwajalein, Asia/Anadyr, Pacific/Majuro, Pacific/Wake, Pacific/Nauru, Pacific/Fiji, Pacific/Wallis]

Instant: 2021-03-23T04:30:00Z in: [Australia/Sydney, Australia/LHI, Pacific/Efate, Asia/Magadan, Antarctica/Casey, Antarctica/Macquarie, Australia/Lord_Howe, Australia/Victoria, Etc/GMT-11, Pacific/Bougainville, Asia/Srednekolymsk, Australia/Tasmania, Australia/Currie, Pacific/Pohnpei, Australia/Melbourne, Pacific/Noumea, Australia/Hobart, Pacific/Guadalcanal, Pacific/Ponape, Australia/ACT, Australia/Canberra, Australia/NSW, Pacific/Kosrae, Asia/Sakhalin]

Instant: 2021-03-23T05:00:00Z in: [Australia/Adelaide, Australia/South, Australia/Broken_Hill, Australia/Yancowinna]

Instant: 2021-03-23T05:30:00Z in: [Pacific/Port_Moresby, Asia/Vladivostok, Pacific/Saipan, Asia/Ust-Nera, Antarctica/DumontDUrville, Etc/GMT-10, Pacific/Truk, Australia/Lindeman, Pacific/Chuuk, Australia/Brisbane, Pacific/Guam, Pacific/Yap, Australia/Queensland]

Instant: 2021-03-23T06:00:00Z in: [Australia/North, Australia/Darwin]

Instant: 2021-03-23T06:30:00Z in: [Asia/Pyongyang, Asia/Tokyo, Asia/Yakutsk, Asia/Jayapura, Asia/Dili, Japan, Asia/Khandyga, Pacific/Palau, Asia/Chita, Etc/GMT-9, Asia/Seoul, ROK]

Instant: 2021-03-23T06:45:00Z in: [Australia/Eucla]

Instant: 2021-03-23T07:30:00Z in: [PRC, Singapore, Hongkong, Asia/Hong_Kong, Asia/Taipei, Asia/Ulan_Bator, Asia/Manila, Asia/Irkutsk, Asia/Ujung_Pandang, Asia/Harbin, Asia/Kuching, Asia/Chongqing, Australia/Perth, Asia/Kuala_Lumpur, Asia/Ulaanbaatar, Asia/Chungking, Asia/Macao, Asia/Shanghai, Asia/Brunei, Asia/Macau, Asia/Choibalsan, Australia/West, Asia/Singapore, Asia/Makassar, Etc/GMT-8]

Instant: 2021-03-23T08:30:00Z in: [Asia/Vientiane, Asia/Ho_Chi_Minh, Asia/Tomsk, Asia/Phnom_Penh, Asia/Jakarta, Asia/Hovd, Asia/Barnaul, Asia/Krasnoyarsk, Asia/Pontianak, Asia/Bangkok, Asia/Saigon, Asia/Novokuznetsk, Asia/Novosibirsk, Indian/Christmas, Antarctica/Davis, Etc/GMT-7]

Instant: 2021-03-23T09:00:00Z in: [Asia/Yangon, Indian/Cocos, Asia/Rangoon]

Instant: 2021-03-23T09:30:00Z in: [Asia/Dacca, Asia/Thimbu, Asia/Omsk, Asia/Qostanay, Asia/Almaty, Asia/Dhaka, Indian/Chagos, Asia/Kashgar, Asia/Urumqi, Antarctica/Vostok, Asia/Bishkek, Asia/Thimphu, Etc/GMT-6]

Instant: 2021-03-23T09:45:00Z in: [Asia/Katmandu, Asia/Kathmandu]

Instant: 2021-03-23T10:00:00Z in: [Asia/Calcutta, Asia/Colombo, Asia/Kolkata]

Instant: 2021-03-23T10:30:00Z in: [Asia/Aqtobe, Asia/Samarkand, Indian/Kerguelen, Asia/Oral, Asia/Ashgabat, Asia/Dushanbe, Asia/Aqtau, Asia/Ashkhabad, Asia/Tashkent, Antarctica/Mawson, Asia/Karachi, Asia/Atyrau, Asia/Yekaterinburg, Etc/GMT-5, Asia/Qyzylorda, Indian/Maldives]

Instant: 2021-03-23T11:00:00Z in: [Asia/Kabul, Asia/Tehran, Iran]

Instant: 2021-03-23T11:30:00Z in: [Indian/Mahe, Indian/Mauritius, Europe/Astrakhan, Indian/Reunion, Asia/Yerevan, Europe/Ulyanovsk, Asia/Dubai, Asia/Muscat, Asia/Tbilisi, Europe/Samara, Europe/Saratov, Europe/Volgograd, Etc/GMT-4, Asia/Baku]

Instant: 2021-03-23T12:30:00Z in: [Asia/Aden, Asia/Qatar, Africa/Nairobi, Antarctica/Syowa, Africa/Juba, Asia/Riyadh, Europe/Moscow, Asia/Bahrain, Africa/Mogadishu, Africa/Dar_es_Salaam, Asia/Baghdad, Asia/Kuwait, Africa/Addis_Ababa, Asia/Istanbul, Africa/Djibouti, Europe/Kirov, Africa/Asmara, Africa/Asmera, Europe/Simferopol, Indian/Antananarivo, Africa/Kampala, Indian/Mayotte, W-SU, Turkey, Europe/Istanbul, Etc/GMT-3, Indian/Comoro, Europe/Minsk]

Instant: 2021-03-23T13:30:00Z in: [Europe/Kiev, Asia/Hebron, Egypt, Europe/Zaporozhye, Asia/Nicosia, Africa/Lusaka, Africa/Gaborone, Africa/Maputo, Europe/Kaliningrad, Libya, Africa/Cairo, Africa/Windhoek, Europe/Mariehamn, Africa/Mbabane, Europe/Vilnius, Asia/Gaza, Europe/Chisinau, Asia/Famagusta, Africa/Maseru, Asia/Amman, Africa/Lubumbashi, Europe/Bucharest, Europe/Uzhgorod, Europe/Helsinki, Asia/Beirut, Africa/Harare, Asia/Tel_Aviv, Africa/Kigali, Europe/Sofia, Europe/Tallinn, Africa/Khartoum, EET, Europe/Tiraspol, Africa/Johannesburg, Europe/Nicosia, Asia/Damascus, Africa/Bujumbura, Asia/Jerusalem, Europe/Athens, Africa/Tripoli, Etc/GMT-2, Israel, Africa/Blantyre, Europe/Riga]

Instant: 2021-03-23T14:30:00Z in: [Europe/Ljubljana, Africa/Libreville, Europe/Berlin, Africa/El_Aaiun, Europe/Oslo, Europe/Stockholm, Europe/Budapest, Europe/Bratislava, Europe/San_Marino, Europe/Zagreb, Europe/Copenhagen, Europe/Malta, Europe/Brussels, Europe/Vienna, Africa/Douala, Europe/Busingen, Europe/Warsaw, CET, Africa/Malabo, Etc/GMT-1, Europe/Podgorica, Europe/Skopje, Europe/Paris, Africa/Ndjamena, Europe/Sarajevo, Europe/Tirane, Africa/Bangui, Europe/Luxembourg, Europe/Belgrade, Arctic/Longyearbyen, MET, Africa/Casablanca, Africa/Lagos, Europe/Rome, Africa/Brazzaville, Africa/Luanda, Africa/Porto-Novo, Atlantic/Jan_Mayen, Africa/Ceuta, Africa/Algiers, Europe/Zurich, Europe/Amsterdam, Poland, Europe/Vatican, Europe/Gibraltar, Africa/Kinshasa, Europe/Madrid, Europe/Vaduz, Africa/Niamey, Europe/Prague, Africa/Tunis, Europe/Andorra, Europe/Monaco]

Instant: 2021-03-23T15:30:00Z in: [UTC, UCT, Portugal, Iceland, Zulu, Africa/Ouagadougou, Europe/Lisbon, Etc/Universal, Europe/London, Atlantic/Faeroe, Africa/Dakar, Etc/GMT, Atlantic/Canary, Africa/Lome, Universal, Africa/Freetown, Africa/Sao_Tome, GMT, Greenwich, Etc/GMT-0, Europe/Jersey, GB-Eire, Africa/Bissau, Europe/Belfast, Africa/Abidjan, Atlantic/Reykjavik, Africa/Monrovia, WET, Atlantic/St_Helena, Etc/Greenwich, Etc/GMT0, Africa/Bamako, Eire, Europe/Guernsey, Africa/Timbuktu, Atlantic/Madeira, GB, Africa/Accra, Africa/Conakry, Atlantic/Faroe, Etc/UTC, Etc/UCT, GMT0, Europe/Dublin, Etc/Zulu, Africa/Nouakchott, Europe/Isle_of_Man, Antarctica/Troll, Etc/GMT+0, Africa/Banjul, America/Danmarkshavn]

Instant: 2021-03-23T16:30:00Z in: [America/Scoresbysund, Atlantic/Cape_Verde, Atlantic/Azores, Etc/GMT+1]

Instant: 2021-03-23T17:30:00Z in: [Atlantic/South_Georgia, Brazil/DeNoronha, Etc/GMT+2, America/Miquelon, America/Noronha]

Instant: 2021-03-23T18:00:00Z in: [America/St_Johns, Canada/Newfoundland]

Instant: 2021-03-23T18:30:00Z in: [America/Argentina/San_Juan, America/Cordoba, America/Sao_Paulo, America/Thule, America/Argentina/Ushuaia, America/Mendoza, America/Moncton, America/Santarem, Canada/Atlantic, America/Asuncion, America/Belem, America/Montevideo, America/Argentina/ComodRivadavia, Atlantic/Bermuda, America/Jujuy, America/Fortaleza, America/Argentina/La_Rioja, Brazil/East, America/Recife, America/Buenos_Aires, Antarctica/Palmer, America/Bahia, America/Goose_Bay, America/Argentina/Jujuy, America/Maceio, America/Argentina/Tucuman, America/Argentina/Cordoba, America/Paramaribo, America/Argentina/Mendoza, America/Nuuk, America/Punta_Arenas, America/Araguaina, America/Argentina/Rio_Gallegos, America/Cayenne, Chile/Continental, America/Halifax, America/Argentina/Buenos_Aires, Antarctica/Rothera, America/Catamarca, America/Godthab, America/Argentina/Salta, Etc/GMT+3, America/Argentina/San_Luis, America/Rosario, Atlantic/Stanley, America/Argentina/Catamarca, America/Santiago, America/Glace_Bay]

Instant: 2021-03-23T19:30:00Z in: [America/Indianapolis, America/Cuiaba, America/Iqaluit, America/Curacao, America/Marigot, America/Blanc-Sablon, America/Indiana/Winamac, America/Guyana, America/Martinique, America/Kentucky/Monticello, Brazil/West, America/Boa_Vista, America/Aruba, America/St_Vincent, America/Grenada, America/Puerto_Rico, America/Tortola, America/Porto_Velho, America/Kentucky/Louisville, America/Manaus, America/Port_of_Spain, America/New_York, America/Indiana/Petersburg, America/Indiana/Indianapolis, America/Santo_Domingo, US/Eastern, America/St_Kitts, SystemV/AST4, America/Caracas, America/Dominica, America/Guadeloupe, Canada/Eastern, America/Port-au-Prince, America/St_Barthelemy, America/La_Paz, America/Nipigon, America/Indiana/Vevay, America/Campo_Grande, America/Fort_Wayne, EST5EDT, America/St_Thomas, America/Anguilla, US/East-Indiana, America/Virgin, America/Thunder_Bay, America/Grand_Turk, SystemV/AST4ADT, America/St_Lucia, America/Pangnirtung, America/Montserrat, America/Havana, America/Toronto, America/Indiana/Marengo, US/Michigan, America/Barbados, Cuba, America/Indiana/Vincennes, America/Nassau, America/Kralendijk, America/Antigua, America/Louisville, America/Lower_Princes, America/Montreal, America/Detroit, Etc/GMT+4]

Instant: 2021-03-23T20:30:00Z in: [America/Matamoros, America/Guayaquil, Brazil/Acre, America/North_Dakota/New_Salem, America/Coral_Harbour, America/North_Dakota/Center, America/Winnipeg, America/Indiana/Knox, America/Rankin_Inlet, America/Cancun, America/Cayman, America/Panama, America/North_Dakota/Beulah, CST6CDT, Pacific/Easter, America/Knox_IN, America/Lima, America/Bogota, America/Indiana/Tell_City, America/Menominee, America/Resolute, America/Porto_Acre, US/Central, US/Indiana-Starke, SystemV/EST5, SystemV/EST5EDT, America/Chicago, Chile/EasterIsland, America/Jamaica, Canada/Central, America/Eirunepe, America/Atikokan, America/Rainy_River, America/Rio_Branco, Jamaica, Etc/GMT+5]

Instant: 2021-03-23T21:30:00Z in: [America/Inuvik, America/Yellowknife, America/Regina, America/Boise, America/El_Salvador, America/Costa_Rica, America/Shiprock, America/Denver, America/Guatemala, America/Belize, SystemV/CST6CDT, Mexico/General, America/Swift_Current, America/Bahia_Banderas, America/Managua, Canada/Mountain, America/Cambridge_Bay, Navajo, America/Ojinaga, MST7MDT, America/Monterrey, America/Merida, Pacific/Galapagos, America/Mexico_City, America/Edmonton, US/Mountain, America/Tegucigalpa, Canada/Saskatchewan, Etc/GMT+6, SystemV/CST6]

Instant: 2021-03-23T22:30:00Z in: [America/Tijuana, America/Santa_Isabel, US/Arizona, Canada/Pacific, Canada/Yukon, Mexico/BajaSur, America/Chihuahua, SystemV/MST7MDT, America/Creston, America/Phoenix, America/Dawson_Creek, America/Los_Angeles, America/Whitehorse, America/Ensenada, America/Dawson, America/Mazatlan, PST8PDT, America/Hermosillo, America/Vancouver, SystemV/MST7, Etc/GMT+7, America/Fort_Nelson, US/Pacific, Mexico/BajaNorte]

Instant: 2021-03-23T23:30:00Z in: [America/Anchorage, America/Yakutat, America/Sitka, Etc/GMT+8, America/Metlakatla, Pacific/Pitcairn, SystemV/PST8, SystemV/PST8PDT, America/Juneau, America/Nome, US/Alaska]

Instant: 2021-03-24T00:30:00Z in: [Etc/GMT+9, America/Adak, US/Aleutian, America/Atka, SystemV/YST9, SystemV/YST9YDT, Pacific/Gambier]

Instant: 2021-03-24T01:00:00Z in: [Pacific/Marquesas]

Instant: 2021-03-24T01:30:00Z in: [Etc/GMT+10, Pacific/Honolulu, Pacific/Rarotonga, Pacific/Tahiti, US/Hawaii, Pacific/Johnston, SystemV/HST10]

Instant: 2021-03-24T02:30:00Z in: [Pacific/Pago_Pago, Pacific/Midway, Pacific/Niue, Pacific/Samoa, Etc/GMT+11, US/Samoa]

Instant: 2021-03-24T03:30:00Z in: [Etc/GMT+12]

您要求:

returns all Instants which are in the given time zone

每个时区每个 LocalDateTime 只有一个 Instant。带时间的日期在一个时区内只能存在一次。

对于给定的一对 LocalDateTimeZoneId,列表中的所有时刻都将具有相同的值,因此创建这样的列表是没有用的。我相信您想要的是 ZonedDateTime 的列表,该列表对于该对具有相同的值,您可以按如下方式获得:

// ZonedDateTime for the given pair of LocalDateTime and ZoneId
ZonedDateTime zdt = dt.atZone(zone);
ZoneOffset offset = zdt.getOffset();

return ZoneId
        .getAvailableZoneIds()                       // List of timezone names
        .stream()
        .map(tz -> dt.atZone(ZoneId.of(tz)))         // Map the timezone to ZonedDateTime for dt
        .filter(zt -> zt.getOffset().equals(offset)) // Keep only those ZonedDateTimes whose offset is equal to that of zdt
        .collect(Collectors.toList());

演示:

import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.ZoneOffset;
import java.time.ZonedDateTime;
import java.util.List;
import java.util.stream.Collectors;

public class Main {
    public static void main(String[] args) {
        // Test
        ZoneId zoneId = ZoneId.of("America/New_York");
        LocalDateTime dt = LocalDateTime.now(zoneId);
        localToZonedDateTimes(dt, zoneId).forEach(System.out::println);
    }

    static List<ZonedDateTime> localToZonedDateTimes(LocalDateTime dt, ZoneId zone) {
        // ZonedDateTime for the given pair of LocalDateTime and ZoneId
        ZonedDateTime zdt = dt.atZone(zone);
        ZoneOffset offset = zdt.getOffset();

        return ZoneId
                .getAvailableZoneIds()                       // List of timezone names
                .stream()
                .map(tz -> dt.atZone(ZoneId.of(tz)))         // Map the timezone to ZonedDateTime for dt
                .filter(zt -> zt.getOffset().equals(offset)) // Keep only those ZonedDateTimes whose offset is equal to that of zdt
                .collect(Collectors.toList());
    }
}

输出:

2021-03-12T16:48:42.368606-05:00[America/Panama]
2021-03-12T16:48:42.368606-05:00[America/Indiana/Petersburg]
2021-03-12T16:48:42.368606-05:00[America/Eirunepe]
2021-03-12T16:48:42.368606-05:00[America/Grand_Turk]
2021-03-12T16:48:42.368606-05:00[Cuba]
2021-03-12T16:48:42.368606-05:00[Etc/GMT+5]
2021-03-12T16:48:42.368606-05:00[Pacific/Easter]
2021-03-12T16:48:42.368606-05:00[America/Fort_Wayne]
2021-03-12T16:48:42.368606-05:00[America/Havana]
2021-03-12T16:48:42.368606-05:00[America/Porto_Acre]
2021-03-12T16:48:42.368606-05:00[US/Michigan]
2021-03-12T16:48:42.368606-05:00[America/Louisville]
2021-03-12T16:48:42.368606-05:00[America/Guayaquil]
2021-03-12T16:48:42.368606-05:00[America/Indiana/Vevay]
2021-03-12T16:48:42.368606-05:00[America/Indiana/Vincennes]
2021-03-12T16:48:42.368606-05:00[America/Indianapolis]
2021-03-12T16:48:42.368606-05:00[America/Iqaluit]
2021-03-12T16:48:42.368606-05:00[America/Kentucky/Louisville]
2021-03-12T16:48:42.368606-05:00[EST5EDT]
2021-03-12T16:48:42.368606-05:00[America/Nassau]
2021-03-12T16:48:42.368606-05:00[America/Jamaica]
2021-03-12T16:48:42.368606-05:00[America/Atikokan]
2021-03-12T16:48:42.368606-05:00[America/Kentucky/Monticello]
2021-03-12T16:48:42.368606-05:00[America/Coral_Harbour]
2021-03-12T16:48:42.368606-05:00[America/Cayman]
2021-03-12T16:48:42.368606-05:00[Chile/EasterIsland]
2021-03-12T16:48:42.368606-05:00[America/Indiana/Indianapolis]
2021-03-12T16:48:42.368606-05:00[America/Thunder_Bay]
2021-03-12T16:48:42.368606-05:00[America/Indiana/Marengo]
2021-03-12T16:48:42.368606-05:00[America/Bogota]
2021-03-12T16:48:42.368606-05:00[SystemV/EST5]
2021-03-12T16:48:42.368606-05:00[US/Eastern]
2021-03-12T16:48:42.368606-05:00[Canada/Eastern]
2021-03-12T16:48:42.368606-05:00[America/Port-au-Prince]
2021-03-12T16:48:42.368606-05:00[America/Nipigon]
2021-03-12T16:48:42.368606-05:00[Brazil/Acre]
2021-03-12T16:48:42.368606-05:00[US/East-Indiana]
2021-03-12T16:48:42.368606-05:00[America/Cancun]
2021-03-12T16:48:42.368606-05:00[America/Lima]
2021-03-12T16:48:42.368606-05:00[America/Rio_Branco]
2021-03-12T16:48:42.368606-05:00[America/Detroit]
2021-03-12T16:48:42.368606-05:00[Jamaica]
2021-03-12T16:48:42.368606-05:00[America/Pangnirtung]
2021-03-12T16:48:42.368606-05:00[America/Montreal]
2021-03-12T16:48:42.368606-05:00[America/Indiana/Winamac]
2021-03-12T16:48:42.368606-05:00[America/New_York]
2021-03-12T16:48:42.368606-05:00[America/Toronto]
2021-03-12T16:48:42.368606-05:00[SystemV/EST5EDT]

Trail: Date Time.

了解有关现代日期时间的更多信息 API

是的✔️

编辑

米。 Prokhorov 使用 ZoneRules.getValidOffset() 的想法给出了比我原来的答案更优雅的代码。这是一个根据要求 returns 列表 Instants 的版本:

public static List<Instant> localToInstants(LocalDateTime dt, ZoneId zone) {
    return zone.getRules()
            .getValidOffsets(dt)
            .stream()
            .map(dt::atOffset)
            .map(OffsetDateTime::toInstant)
            .collect(Collectors.toList());
}

让我们在几个重要的例子上试试看。马耳他将于 3 月 28 日过渡到夏令时。凌晨 2 点,时钟拨快至 3 点。因此,时间 2:30 在这一天不存在。这意味着我们期望从以下调用中得到一个空列表:

    LocalDateTime dt = LocalDateTime.of(2021, Month.MARCH, 28, 2, 30);
    System.out.println(localToInstants(dt, ZoneId.of("Europe/Malta")));

输出确实是:

[]

这是Java打印空列表的方式。工作原理:由于时间不存在,ZoneRules.getValidOffsets() return 是一个空列表。其余的很无聊:没有偏移量可以转换为 OffsetDateTime 并进一步转换为 Instant,因此空列表是 returned.

我的另一个例子来自 Eater Island。根据我的 Java 9 夏令时将在 5 月 8 日结束。在 22 时时钟将拨回到 21。所以时间 21:30 出现了两次。让我们看看:

    LocalDateTime dt = LocalDateTime.of(2021, Month.MAY, 8, 21, 30);
    System.out.println(localToInstants(dt, ZoneId.of("Pacific/Easter")));

[2021-05-09T02:30:00Z, 2021-05-09T03:30:00Z]

由于 UTC 偏移量从 -05:00 变为 -06:00,所以时刻是正确的。在这种情况下,getValidOffsets() return 编辑了两个有效偏移量,-05:00 和 -06:00,因此代码生成了两个 OffsetDateTime 对象,这些对象又被转换为两个不同的 Instant 对象。

原回答

如果有人有兴趣获得合适的 ZonedDateTime 对象,我将保留此立场。

public static List<Instant> localToInstants(LocalDateTime dt, ZoneId zone) {
    return Stream.of(dt.atZone(zone).withEarlierOffsetAtOverlap(),
                     dt.atZone(zone).withLaterOffsetAtOverlap())
            .filter(zdt -> zdt.toLocalDateTime().equals(dt))
            .map(ZonedDateTime::toInstant)
            .distinct()
            .collect(Collectors.toList());
}

让我们在几个重要的例子上试试看。马耳他将于 3 月 28 日过渡到夏令时。凌晨 2 点,时钟拨快至 3 点。因此,时间 2:30 在这一天不存在。这意味着我们期望从以下调用中得到一个空列表:

    LocalDateTime dt = LocalDateTime.of(2021, Month.MARCH, 28, 2, 30);
    System.out.println(localToInstants(dt, ZoneId.of("Europe/Malta")));

输出确实是:

[]

这是Java打印空列表的方式。工作原理:由于时间不存在,dt.atZone(zone) 给我们 3:30 而不是 2:30。 Java 添加间隔的长度,夏令时过渡通常为一小时。在这种情况下,对 withEarlierOffsetAtOverlap()withLaterOffsetAtOverlap() 的调用没有任何区别(我将对它们 return ),所以我们只得到相同的 ZonedDateTime 两次。对 filter() 的调用造成了差异:我们将 ZonedDateTime 转换回 LocalDateTime 并发现我们没有得到相同的时间,因此我们丢弃了结果。剩下的很无聊:没有 ZonedDateTime 可以转换为 Instant,所以我们最终得到一个空列表。

我的另一个例子来自 Eater Island。根据我的 Java 9 夏令时将在 5 月 8 日结束。在 22 时时钟将拨回到 21。所以时间 21:30 出现了两次。让我们看看:

    LocalDateTime dt = LocalDateTime.of(2021, Month.MAY, 8, 21, 30);
    System.out.println(localToInstants(dt, ZoneId.of("Pacific/Easter")));

[2021-05-09T02:30:00Z, 2021-05-09T03:30:00Z]

由于 UTC 偏移量从 -05:00 变为 -06:00,所以时刻是正确的。它是如何工作的:这里是对 withEarlierOffsetAtOverlap()withLaterOffsetAtOverlap() 的调用发挥作用的地方。 dt.atZone(zone) 给了我们一个选项(2021-05-08T21:30-05:00[Pacific/Easter],所以较早的一个,但没有一个理智的人会记住它)。因为 Java 知道此时有重叠,所以 withEarlierOffsetAtOverlap()withLaterOffsetAtOverlap() 给了我们两种不同的可能性。由于两者都转换回正确的 LocalDateTime,因此不会过滤掉任何内容。由于两者是不同的时刻,distinct() 也不会过滤掉任何东西。我们最终得到两个 Instant 个对象。

文档 link

ZoneRules.getValidOffsets()