Java - Unexpected result from Calendar.set(HOUR_OF_DAY)
JVM版本是1.7。 时区为GMT + 3,偏移180分钟。
我正在执行以下代码来调整
1 2 3 4 5 6 7 8 | final Calendar calendar = Calendar.getInstance(TimeZone.getTimeZone("UTC")); Date date = new Date(1500411600000L); calendar.setTime(date); calendar.set(Calendar.HOUR_OF_DAY, 23); calendar.set(Calendar.MINUTE, 59); calendar.set(Calendar.SECOND, 59); calendar.set(Calendar.MILLISECOND, 999); date = calendar.getTime(); |
我希望
你能帮我找一些时区不可知代码来调整日期时间吗?
您是正确的,在偏移UTC + 3时,您的毫秒值1500411600000对应于2017年7月19日午夜(一天的开始)。在其他偏移量,它对应于7月18日或19日的其他时间。
java.time
假设你在自己的时区里有午夜并不是巧合,那个值真的应该代表一个日期,而不是一个时间,我建议你使用
1 2 3 4 5 | ZoneId yourTimeZone = ZoneId.of("Europe/Riga"); LocalDate date = Instant.ofEpochMilli(1500411600000L) .atZone(yourTimeZone) .toLocalDate(); System.out.println(date); |
这打印出预期的
1 | 2017-07-19 |
如果不是欧洲/里加,请替换正确的时区,或者使用
我怀疑你真的不想在一天结束时,即使在你的问题中你试图设置它。如果这是为了确定某个时间点是否在一天结束之前,则将其与第二天的开始时间进行比较,并要求它严格地在之前。这可以省去奇怪的分钟,秒和秒的分数。
1 | ZonedDateTime startOfNextDay = date.plusDays(1).atStartOfDay(yourTimeZone); |
你在这个问题上尝试了什么
我相信当用
1 2 3 4 | OffsetDateTime endOfDay = Instant.ofEpochMilli(1500411600000L) .atOffset(ZoneOffset.UTC) .with(LocalTime.MAX); System.out.println(endOfDay); |
这打印
1 | 2017-07-18T23:59:59.999999999Z |
(7月18日UTC结束时;
问题:我可以在我的Java版本中使用
是的你可以。你只需要至少使用Java 6。
- 在Java 8及更高版本中,新的API内置。
- 在Java 6和7中获取ThreeTen Backport,这是新类的后端(JST 310的ThreeTen)。
- 在Android上,使用Android版的ThreeTen Backport。它被称为ThreeTenABP,在这个问题中有一个彻底的解释:如何在Android项目中使用ThreeTenABP。
要学习使用
问题比我的问题中描述的要大。它源于用户时区的错误管理日期/时间。在我的应用程序中,时间戳是在用户的时区发送的,然后在服务器的时区中进行了评估,但没有考虑时区差异。我试图解决这个问题并面对问题中描述的问题。
我听了@ ThomasEdwin建议使用Joda Time,我很乐意分享这个解决方案:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | long userTimezoneOffset = 180; // it's a parameter submitted by client app Date date = new Date(1500411600000L); // it's another parameter submitted by client app final DateTimeZone zone = DateTimeZone.forOffsetMillis((int) TimeUnit.MINUTES.toMillis(userTimezoneOffset)); final DateTimeZone serverZone = DateTimeZone.getDefault(); MutableDateTime dateTime = new MutableDateTime(date, zone); dateTime.setHourOfDay(23); dateTime.setMinuteOfHour(59); dateTime.setSecondOfMinute(59); dateTime.setMillisOfSecond(999); dateTime.setZoneRetainFields(serverZone); date = dateTime.toDate(); // now date.toString() returns expected result |
此外,我发现
使用
1 2 3 4 5 6 7 8 9 | final Calendar calendar = Calendar.getInstance(TimeZone.getTimeZone("UTC")); Date date = new Date(1500411600000L); calendar.clear(); // To reset _all_ fields, incl. the time zone offset ZONE_OFFSET. calendar.setTime(date); calendar.set(Calendar.HOUR_OF_DAY, 23); calendar.set(Calendar.MINUTE, 59); calendar.set(Calendar.SECOND, 59); calendar.set(Calendar.MILLISECOND, 999); date = calendar.getTime(); |
当然,这可能是切换到新的Java时间API的正确参数。
请参阅此处的线程,其中解释了有关日期和时区的问题。
如何设置java.util.Date的时区?
Date对象将具有正确的调整时间,但在显示时,输出将使用您当地的时区。您可以使用以下代码强制设置JVM的时区,但这可能会在代码的其他部分产生意外后果。
在理想的世界中,您将使用Java 8日期类或Joda时间库类,它们都提供了一些简单的日期操作方法。
Java 8日期类
你正在使用