Java API 获取一年的夏令时界限
Java API to get daylight saving boundaries for a year
我有一个日期范围(开始日期和结束日期)并且需要知道这是否属于夏令时转换。
是否有任何 Java API 可用于检查这个或任何 Java 代码来实现这个?
当然有。也不止一个。使用的标准 API 是 java.time
.
很明显,您首先需要确定您想要的时区。
您将问题标记为 gmt,这很简单:GMT 没有夏令时(夏令时),因此您的范围永远不会发生转换。如果这就是您的意思,则无需继续阅读。
北美和欧盟的夏令时转换日期不一样,在南半球则完全不同。此外,许多时区根本不适用夏令时。因此,从 ZoneId.of()
获取您的预期时区,提供 continent/city
形式的字符串,例如 Europe/Stockholm
。它接受许多城市,我认为每个时区至少有一个,每个国家至少有一个。使用 ZoneId.getRules()
得到一个 ZoneRules
对象。请检查 the documentation 以了解您可以使用此对象执行的所有操作。我想我会尝试 nextTransistion()
传递你的开始日期。如果我得到 null
返回,则范围内不能进行转换(可能该区域不应用夏令时)。如果我得到 ZoneOffsetTransition
,请使用它的 getInstant()
并检查 Instant
是否在您的结束日期之前。
java.time
在 JSR-310 中有描述。它内置于 Java 8 及更高版本中。如果您还没有使用 Java 8,请使用 ThreeTen Backport.
您将问题标记为 jodatime,是的,Joda-Time 也应该是一个选项。
Note that Joda-Time is considered to be a largely “finished” project.
No major enhancements are planned. If using Java SE 8, please migrate
to java.time
(JSR-310).
每个 country/region 的夏令时更改发生在不同的日期,因此首先要知道您正在检查的时区的名称。
我正在使用 Joda-Time 和新的 Java Date/Time API 写这个答案,并且都使用 IANA's list of timezone names (in the format Continent/City
). Both API's also avoid to use the 3-letter names because they are ambiguous and not standard.
对于下面的代码,我将使用 America/Sao_Paulo
(我居住的时区,夏令时每年都会更改),但您可以将其替换为您想要的时区。
下面的代码向您展示了如何检查一个日期是否在 DST 中,以及如何找到下一个 DST 更改发生的日期。因此,如果您有开始日期和结束日期,并且想知道两者是否都在 DST 更改范围内,则可以检查两者是否都在 DST 范围内,还可以找到下一个和上一个 DST 更改(并检查日期是否介于这些更改 - 我不清楚应该如何进行检查)。
另请注意,Joda-Time 处于维护模式并且正在被新的 APIs 取代,因此我不建议使用它开始一个新项目。即使在 joda's website 它说:“请注意,Joda-Time 被认为是一个基本上“完成”的项目。没有计划进行重大改进。如果使用 Java SE 8,请迁移到 java.time (JSR-310).".
乔达时间
可以使用org.joda.time.DateTimeZone
class。要了解所有可用时区,请调用 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新Date/TimeAPI
如果您使用的是 Java 8,new java.time API 已经自带了。
如果您使用 Java <= 7,您可以使用 ThreeTen Backport, a great backport for Java 8's new date/time classes. And for Android, there's the ThreeTenABP (more on how to use it ).
下面的代码适用于两者。
唯一的区别是包名称(在 Java 8 中是 java.time
,在 ThreeTen Backport(或 Android 的 ThreeTenABP)中是 org.threeten.bp
),但是 classes和方法names是一样的。
代码与 Joda-Time 的版本非常相似。主要区别:
- 虽然 Joda-Time 有
isStandardOffset()
检查日期是否为夏令时 而不是 ,但新的 API 有 isDaylightSavings()
检查如果日期是夏令时。
- Joda-Time 直接在
DateTimeZone
class 中提供方法,但新的 API 有专门的 class 用于其 DST 规则(java.time.zone.ZoneRules
)
- 下一个和上一个转换的方法 return
java.time.zone.ZoneOffsetTransition
而不是直接 returning 日期(此对象提供有关 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()
。
我有一个日期范围(开始日期和结束日期)并且需要知道这是否属于夏令时转换。
是否有任何 Java API 可用于检查这个或任何 Java 代码来实现这个?
当然有。也不止一个。使用的标准 API 是 java.time
.
很明显,您首先需要确定您想要的时区。
您将问题标记为 gmt,这很简单:GMT 没有夏令时(夏令时),因此您的范围永远不会发生转换。如果这就是您的意思,则无需继续阅读。
北美和欧盟的夏令时转换日期不一样,在南半球则完全不同。此外,许多时区根本不适用夏令时。因此,从 ZoneId.of()
获取您的预期时区,提供 continent/city
形式的字符串,例如 Europe/Stockholm
。它接受许多城市,我认为每个时区至少有一个,每个国家至少有一个。使用 ZoneId.getRules()
得到一个 ZoneRules
对象。请检查 the documentation 以了解您可以使用此对象执行的所有操作。我想我会尝试 nextTransistion()
传递你的开始日期。如果我得到 null
返回,则范围内不能进行转换(可能该区域不应用夏令时)。如果我得到 ZoneOffsetTransition
,请使用它的 getInstant()
并检查 Instant
是否在您的结束日期之前。
java.time
在 JSR-310 中有描述。它内置于 Java 8 及更高版本中。如果您还没有使用 Java 8,请使用 ThreeTen Backport.
您将问题标记为 jodatime,是的,Joda-Time 也应该是一个选项。
Note that Joda-Time is considered to be a largely “finished” project. No major enhancements are planned. If using Java SE 8, please migrate to
java.time
(JSR-310).
每个 country/region 的夏令时更改发生在不同的日期,因此首先要知道您正在检查的时区的名称。
我正在使用 Joda-Time 和新的 Java Date/Time API 写这个答案,并且都使用 IANA's list of timezone names (in the format Continent/City
). Both API's also avoid to use the 3-letter names because they are ambiguous and not standard.
对于下面的代码,我将使用 America/Sao_Paulo
(我居住的时区,夏令时每年都会更改),但您可以将其替换为您想要的时区。
下面的代码向您展示了如何检查一个日期是否在 DST 中,以及如何找到下一个 DST 更改发生的日期。因此,如果您有开始日期和结束日期,并且想知道两者是否都在 DST 更改范围内,则可以检查两者是否都在 DST 范围内,还可以找到下一个和上一个 DST 更改(并检查日期是否介于这些更改 - 我不清楚应该如何进行检查)。
另请注意,Joda-Time 处于维护模式并且正在被新的 APIs 取代,因此我不建议使用它开始一个新项目。即使在 joda's website 它说:“请注意,Joda-Time 被认为是一个基本上“完成”的项目。没有计划进行重大改进。如果使用 Java SE 8,请迁移到 java.time (JSR-310).".
乔达时间
可以使用org.joda.time.DateTimeZone
class。要了解所有可用时区,请调用 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新Date/TimeAPI
如果您使用的是 Java 8,new java.time API 已经自带了。
如果您使用 Java <= 7,您可以使用 ThreeTen Backport, a great backport for Java 8's new date/time classes. And for Android, there's the ThreeTenABP (more on how to use it
下面的代码适用于两者。
唯一的区别是包名称(在 Java 8 中是 java.time
,在 ThreeTen Backport(或 Android 的 ThreeTenABP)中是 org.threeten.bp
),但是 classes和方法names是一样的。
代码与 Joda-Time 的版本非常相似。主要区别:
- 虽然 Joda-Time 有
isStandardOffset()
检查日期是否为夏令时 而不是 ,但新的 API 有isDaylightSavings()
检查如果日期是夏令时。 - Joda-Time 直接在
DateTimeZone
class 中提供方法,但新的 API 有专门的 class 用于其 DST 规则(java.time.zone.ZoneRules
) - 下一个和上一个转换的方法 return
java.time.zone.ZoneOffsetTransition
而不是直接 returning 日期(此对象提供有关 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()
。