我有两个字符串作为startDate和endDate。这些值例如:
startDate="2019-09-29T06:00:00.000Z"
endDate="2019-10-06T05:59:59.999Z"
现在让我们说这些在“山区时间”中作为startDate的一天的开始和对于endDate的一天的结束。但是由于这些是字符串,我如何使程序理解这些可以转换为Mountain当地时间,例如:
startDate="2019-09-29T00:00:00.000Z"
endDate="2019-10-05T11:59:59.999Z"
并且时区是动态的。我可以从东部时间或任何其他时区获取时间戳字符串。
更新
我意识到我应该提供更多信息。
因此,我输入的山区时间就是一个例子。它可以来自东部时间或任何其他时区。此方法知道的唯一事实是startDate是某个时区中一天的开始,而endDate是该时区中一天的结束。我知道'Z'是UTC时间,但是要找出哪个时区在一天的开始时间(startDate)和一天的结束时间(endDate)产生了该UTC时间并转换回相应的本地时间,这是我面临的挑战正在面对。
答案 0 :(得分:4)
最后的Z
是时区信息,表示offset的UTC 00:00(又名零,又名Zulu),因此首先您将字符串解析为存储该类型的字符串日期,时间和Z
时区。
使用Java 8 Time API,可以是Instant
,OffsetDateTime
或ZonedDateTime
。
如果您的输入始终以Z
结尾,而不是其他偏移量,请使用Instant
。
然后,您将转换为所需的时区,在美国山区时间称为America/Denver
。
示例
String startDate = "2019-09-29T06:00:00.000Z";
String endDate = "2019-10-06T05:59:59.999Z";
ZoneId zone = ZoneId.of("America/Denver");
System.out.println(Instant.parse(startDate).atZone(zone));
System.out.println(OffsetDateTime.parse(startDate).atZoneSameInstant(zone));
System.out.println(ZonedDateTime.parse(startDate).withZoneSameInstant(zone));
System.out.println(Instant.parse(endDate).atZone(zone));
System.out.println(OffsetDateTime.parse(endDate).atZoneSameInstant(zone));
System.out.println(ZonedDateTime.parse(endDate).withZoneSameInstant(zone));
输出
2019-09-29T00:00-06:00[America/Denver]
2019-09-29T00:00-06:00[America/Denver]
2019-09-29T00:00-06:00[America/Denver]
2019-10-05T23:59:59.999-06:00[America/Denver]
2019-10-05T23:59:59.999-06:00[America/Denver]
2019-10-05T23:59:59.999-06:00[America/Denver]
如果您不想在转换后保留时区,则可以通过调用toLocalDateTime()
将其删除,例如
System.out.println(Instant.parse(endDate).atZone(zone).toLocalDateTime());
输出
2019-10-05T23:59:59.999
请注意结尾处没有Z
。
答案 1 :(得分:0)
我不能不动手指,这很有趣。据我了解,您不知道开始和结束字符串来自哪个时区,可能是任何时区。除了依次尝试所有这些方法之外,我们还能做什么?
O(N)
此打印:
String startDate = "2019-09-29T06:00:00.000Z";
String endDate = "2019-10-06T05:59:59.999Z";
LocalTime dayStart = LocalTime.MIN;
LocalTime dayEndEarliset = LocalTime.of(23, 59, 59);
Instant startInstant = Instant.parse(startDate);
Instant endInstant = Instant.parse(endDate);
// Just out of curiosity find candidate time zones
Set<ZoneId> candidateZones = ZoneId.getAvailableZoneIds()
.stream()
.map(ZoneId::of)
.filter(zid -> startInstant.atZone(zid).toLocalTime().equals(dayStart)
&& ! endInstant.atZone(zid).toLocalTime().isBefore(dayEndEarliset))
.collect(Collectors.toSet());
System.out.println("Potential time zones: " + candidateZones);
// Real work: find candidate date(s)
Set<LocalDate> candidateDates = ZoneId.getAvailableZoneIds()
.stream()
.map(ZoneId::of)
.filter(zid -> startInstant.atZone(zid).toLocalTime().equals(dayStart)
&& ! endInstant.atZone(zid).toLocalTime().isBefore(dayEndEarliset))
.map(zid -> startInstant.atZone(zid).toLocalDate())
.collect(Collectors.toSet());
if (candidateDates.isEmpty()) {
System.out.println("Cannot identify a date from the instants");
} else if (candidateDates.size() > 1) {
System.out.println("Ambiguous date, candidates are " + candidateDates);
} else {
System.out.println("The date is " + candidateDates.iterator().next());
}
是的,美国/丹佛是预期的候选时区之一。到目前为止,我已经找到开始日期。您可以以类似的方式找到开始日期和结束日期对。相对于流操作,您可能更喜欢老式循环。
但是,日期不会总是很明确。让我们尝试在太平洋/ Pago_Pago时区中设置一天的间隔。现在是偏移-11:00。
Potential time zones: [America/Inuvik, America/Yellowknife, America/Regina, America/Boise, SystemV/MST7MDT, America/El_Salvador, America/Costa_Rica, America/Shiprock, America/Guatemala, America/Denver, America/Belize, America/Swift_Current, America/Managua, Mexico/BajaSur, Canada/Mountain, America/Cambridge_Bay, Navajo, America/Chihuahua, America/Ojinaga, MST7MDT, Pacific/Galapagos, America/Mazatlan, US/Mountain, America/Edmonton, America/Tegucigalpa, Canada/Saskatchewan, Etc/GMT+6, SystemV/CST6]
The date is 2019-09-29
现在程序的输出为:
ZoneId zone = ZoneId.of("Pacific/Pago_Pago");
LocalDate testDate = LocalDate.of(2019, Month.OCTOBER, 2);
String startDate = testDate.atStartOfDay(zone).toInstant().toString();
String endDate = testDate.atTime(LocalTime.of(23, 59, 59, 999_000_000))
.atZone(zone)
.toInstant()
.toString();
这是因为还有时区,偏移为+13:00。我们可以说偏移量必须是-11:00或+13:00,但是我们不能确定两者中的哪一个。这样就有两个日期。
使用半开时间间隔
我不确定结束时间是否总是在相关时区的23:59:59.999或有时23:59:59.999999或其他时间。同样,无论我们添加多少个小数,理论上仍然存在在该结束时间之后但仍在同一日期内的时刻。在代码中,我保守地接受23:59:59及之后的任何时间作为结束时间。完全避免疑问的点是:使用半开间隔。如上所示,将间隔的开始表示为00:00:00,将结束日期表示为00:00:00,该日期位于最后一个日期之后的 中。并将开始日期视为包含日期,结束日期视为排除范围。