最初我在寻找Actionscript中的解决方案。这个问题的关键是算法,当时钟必须切换夏令时时,它会检测精确的分钟。
因此,例如在10月25日和31日之间,我们必须检查,如果实际日期是星期日,则是在2点之前或之后......
答案 0 :(得分:4)
没有真正的算法来处理夏令时。基本上每个国家都可以在DST开始和结束时自行决定。我们作为开发人员唯一能做的就是使用某种表来查找它。大多数计算机语言都使用该语言集成了这样的表。
在Java中,您可以使用TimeZone类的inDaylightTime
方法。如果您想知道DST在特定年份开始或结束的确切日期和时间,我建议您使用Joda Time。我看不到使用标准库找到这个的简洁方法。
以下程序是一个例子:(请注意,如果某个时区在某一年没有DST,它可能会产生意外结果)
import org.joda.time.DateTime;
import org.joda.time.DateTimeZone;
public class App {
public static void main(String[] args) {
DateTimeZone dtz = DateTimeZone.forID("Europe/Amsterdam");
System.out.println(startDST(dtz, 2008));
System.out.println(endDST(dtz, 2008));
}
public static DateTime startDST(DateTimeZone zone, int year) {
return new DateTime(zone.nextTransition(new DateTime(year, 1, 1, 0, 0, 0, 0, zone).getMillis()));
}
public static DateTime endDST(DateTimeZone zone, int year) {
return new DateTime(zone.previousTransition(new DateTime(year + 1, 1, 1, 0, 0, 0, 0, zone).getMillis()));
}
}
答案 1 :(得分:1)
Answer by Richters是正确的,应该被接受。
Richters指出,Daylight Saving Time (DST)或其他异常没有逻辑。政治家任意重新定义他们offset-from-UTC中使用的time zones。几周之前,他们经常几乎没有预警,甚至根本没有警告North Korea did。
以下是一些进一步的想法,以及使用现代 java.time 类的示例代码,这些类继续在他的答案中显示的Joda-Time类。
这些更改会在ICANN维护的列表中进行跟踪,称为tzdata,以前称为Olson数据库。您的Java实现,主机操作系统和数据库系统可能都有自己的数据副本,当您将模式更改为您关注的区域时,必须根据需要替换这些副本。这些更改没有逻辑,因此无法以编程方式预测更改。您的代码必须使用 tzdata 的新副本。
因此,例如在10月25日和31日之间,我们必须检查,如果实际日期是星期日,则是在2点之前或之后......
实际上,您无需确定切换点。一个好的日期时间库会自动为您处理。
Java拥有最好的库,业界领先的 java.time 类。当您在特定区域(时区)的某个特定日期询问时间时,如果该时间无效,则会自动进行调整。阅读ZonedDateTime
的文档,了解该调整中使用的算法。
ZoneId z = ZoneId.of( "America/Montreal" );
LocalDate ld = LocalDate.of( 2018 , Month.MARCH , 11 ); // 2018-03-11.
LocalTime lt = LocalTime.of( 2 , 0 ); // 2 AM.
ZonedDateTime zdt = ZonedDateTime.of( ld , lt , z );
请注意,结果是凌晨3点,而不是请求的上午2点。该区域当天没有凌晨2点。所以java.time调整到凌晨3点作为时钟“弹簧前进”一小时。
zdt.toString():2018-03-11T03:00-04:00 [美国/蒙特利尔]
如果您认为需要调查为时区定义的规则,请使用ZoneRules
类。
获取当前使用的DST转换量。
Duration d = z.getRules().getDaylightSavings( Instant.now() ) ;
获取下一次计划的更改,表示为ZoneOffsetTransition
对象。
ZoneId z = ZoneId.of( "America/Montreal" );
ZoneOffsetTransition t = z.getRules().nextTransition( Instant.now() );
String output = "For zone: " + z + ", on " + t.getDateTimeBefore() + " duration change: " + t.getDuration() + " to " + t.getDateTimeAfter();
对于区域:America / Montreal,2018-11-04T02:00持续时间更改:PT-1H至2018-11-04T01:00
以continent/region
的格式指定proper time zone name,例如America/Montreal
,Africa/Casablanca
或Pacific/Auckland
。切勿使用诸如EST
或IST
之类的3-4字母缩写,因为它们不是真正的时区,不是标准化的,甚至不是唯一的(!)。
java.time框架内置于Java 8及更高版本中。这些类取代了麻烦的旧legacy日期时间类,例如java.util.Date
,Calendar
和& SimpleDateFormat
现在位于Joda-Time的maintenance mode项目建议迁移到java.time类。
要了解详情,请参阅Oracle Tutorial。并搜索Stack Overflow以获取许多示例和解释。规范是JSR 310。
您可以直接与数据库交换 java.time 对象。使用符合JDBC driver或更高版本的JDBC 4.2。不需要字符串,不需要java.sql.*
类。
从哪里获取java.time类?
ThreeTen-Extra项目使用其他类扩展java.time。该项目是未来可能添加到java.time的试验场。您可以在此处找到一些有用的课程,例如Interval
,YearWeek
,YearQuarter
和more。