我有一个日期范围(开始日期和结束日期),并且需要知道这是否属于夏令时更改。
是否有任何Java API可用于检查此代码或任何Java代码来实现此目的?
答案 0 :(得分:3)
当然有。还有不止一个。要使用的标准API是java.time
。
很明显,您首先需要确定您想要的时区。
您标记了问题gmt,这很简单:GMT没有夏令时(夏令时),因此您的范围永远不会有转换。如果这是你的意思,你需要不再阅读。
北美和欧盟的夏令时转换日期并不相同,而在南半球,它们却完全不同。此外,许多时区根本不应用DST。因此,请从ZoneId.of()
获取您想要的时区,并提供continent/city
形式的字符串,例如Europe/Stockholm
。它接受了许多城市,我认为每个时区至少有一个,每个国家都有一个。使用ZoneId.getRules()
获取ZoneRules
个对象。请检查the documentation以了解使用此对象可以执行的所有操作。我想我会尝试nextTransistion()
通过你的开始日期。如果我返回null
,则范围内无法进行转换(可能该区域不适用DST)。如果我返回ZoneOffsetTransition
,请使用其getInstant()
并检查Instant
是否位于结束日期之前。
java.time
。它内置于Java 8及更高版本中。如果您尚未使用Java 8,请使用ThreeTen Backport。
你标记了你的问题jodatime,是的,Joda-Time也应该是一个选项。
请注意,Joda-Time被认为是一个很大程度上“完成”的项目。 没有计划重大改进。如果使用Java SE 8,请迁移 到
java.time
(JSR-310)。
答案 1 :(得分:3)
夏令时更改发生在每个国家/地区的不同日期,因此首先要知道的是您正在检查的时区名称。
我正在使用Joda-Time和新的Java Date / Time API编写此答案,并且都使用IANA's list of timezone names(格式为Continent/City
)。这两个API也避免使用3-letter names,因为它们是ambiguous and not standard。
对于下面的代码,我将使用America/Sao_Paulo
(我居住的时区,每年都有DST更改),但您可以将其替换为您想要的时区。
下面的代码显示了如何检查日期是否在夏令时,并找到DST更改发生时的下一个日期。因此,如果您有一个开始和结束日期,并想知道两者是否都在DST更改中,您可以检查两者是否都在DST中,并且还可以找到下一个和之前的DST更改(并检查日期是否介于两者之间)这些变化 - 我不清楚你应该如何进行检查。
还要注意Joda-Time处于维护模式并且正在被新API替换,因此我不建议使用它来启动新项目。即使在joda's website中它也说:“请注意,Joda-Time被认为是一个很大程度上”完成“的项目。没有计划大的增强。如果使用Java SE 8,请迁移到java.time(JSR) -310)。“即可。
您可以使用org.joda.time.DateTimeZone
课程。要了解所有可用的时区,请致电DateTimeZone.getAvailableIDs()
。
下面的代码检查日期是否在DST中,并且还会找到DST更改发生的下一个日期:
// create timezone object
DateTimeZone zone = DateTimeZone.forID("America/Sao_Paulo");
// check if a date is in DST
DateTime inDst = new DateTime(2017, 1, 1, 10, 0, zone);
// isStandardOffset returns false (it's in DST)
System.out.println(zone.isStandardOffset(inDst.getMillis()));
// check when it'll be the next DST change
DateTime nextDstChange = new DateTime(zone.nextTransition(inDst.getMillis()), zone);
System.out.println(nextDstChange); // 2017-02-18T23:00:00.000-03:00
// check if a date is in DST
DateTime noDst = new DateTime(2017, 6, 18, 10, 0, zone);
// isStandardOffset returns true (it's not in DST)
System.out.println(zone.isStandardOffset(noDst.getMillis()));
// check when it'll be the next DST change
nextDstChange = new DateTime(zone.nextTransition(noDst.getMillis()), zone);
System.out.println(nextDstChange); // 2017-10-15T01:00:00.000-02:00
如果您想要找到之前的DST更改(而不是下一次),请拨打previousTransition()
而不是nextTransition()
。
如果您使用的是 Java 8 ,则new java.time API已经原生。
如果您使用的是 Java< = 7 ,则可以使用ThreeTen Backport,这是Java 8新日期/时间类的绝佳后端。对于 Android ,有ThreeTenABP(更多关于如何使用它here)。
以下代码适用于两者。
唯一的区别是包名称(在Java 8中为java.time
,在ThreeTen Backport(或Android的ThreeTenABP)中为org.threeten.bp
),但类和方法名称是相同的
代码与Joda-Time的版本非常相似。主要区别:
isStandardOffset()
来检查DST中的日期不是,但新API有isDaylightSavings()
来检查日期是否在夏令时。 DateTimeZone
类中提供方法,但新API有一个专用于其DST规则的类(java.time.zone.ZoneRules
)java.time.zone.ZoneOffsetTransition
而不是直接返回日期(此对象提供有关DST更改的更多信息,如下所示)。尽管存在这些差异,但这个想法非常相似:
// create timezone object
ZoneId zone = ZoneId.of("America/Sao_Paulo");
// get the timezone's rules
ZoneRules rules = zone.getRules();
// check if a date is in DST
ZonedDateTime inDST = ZonedDateTime.of(2017, 1, 1, 10, 0, 0, 0, zone);
// isDaylightSavings returns true (it's in DST)
System.out.println(rules.isDaylightSavings(inDST.toInstant()));
// check when it'll be the next DST change
ZoneOffsetTransition nextTransition = rules.nextTransition(inDST.toInstant());
// getInstant() returns the UTC instant; atZone converts to the specified timezone
System.out.println(nextTransition.getInstant().atZone(zone)); // 2017-02-18T23:00-03:00[America/Sao_Paulo]
// you can also check the date/time and offset before and after the DST change
// in this case, at 19/02/2017, the clock is moved 1 hour back (from midnight to 11 PM)
ZonedDateTime beforeDST = ZonedDateTime.of(nextTransition.getDateTimeBefore(), nextTransition.getOffsetBefore());
System.out.println(beforeDST); // 2017-02-19T00:00-02:00
ZonedDateTime afterDST = ZonedDateTime.of(nextTransition.getDateTimeAfter(), nextTransition.getOffsetAfter());
System.out.println(afterDST); // 2017-02-18T23:00-03:00
// check if a date is in DST
ZonedDateTime noDST = ZonedDateTime.of(2017, 6, 1, 10, 0, 0, 0, zone);
// isDaylightSavings returns false (it's not in DST)
System.out.println(rules.isDaylightSavings(noDST.toInstant()));
// check when it'll be the next DST change
nextTransition = rules.nextTransition(noDST.toInstant());
// getInstant() returns the UTC instant; atZone converts to the specified timezone
System.out.println(nextTransition.getInstant().atZone(zone)); // 2017-10-15T01:00-02:00[America/Sao_Paulo]
// you can also check the date/time and offset before and after the DST change
// in this case, at 15/10/2017, the clock is moved 1 hour forward (from midnight to 1 AM)
beforeDST = ZonedDateTime.of(nextTransition.getDateTimeBefore(), nextTransition.getOffsetBefore());
System.out.println(beforeDST); // 2017-10-15T00:00-03:00
afterDST = ZonedDateTime.of(nextTransition.getDateTimeAfter(), nextTransition.getOffsetAfter());
System.out.println(afterDST); // 2017-10-15T01:00-02:00
如果您想查找之前的DST更改而不是下一次更改,则可以拨打rules.previousTransition()
而不是rules.nextTransition()
。