You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

为何使用Ada.Calendar计算2011年3月27日与28日的日期差为0天?

为何使用Ada.Calendar计算2011年3月27日与28日的日期差结果为0天?

问题重现

测试代码如下:

with Ada.Calendar;            use Ada.Calendar;
with Ada.Calendar.Arithmetic; use Ada.Calendar.Arithmetic;
with Ada.Text_IO;             use Ada.Text_IO;
procedure main is
   t0 : Time      := Time_Of (Year => 2_011, Month => 3, Day => 27);
   t1 : Time      := Time_Of (Year => 2_011, Month => 3, Day => 28);
   da : Day_Count := t1 - t0;
begin
   Put_Line (da'Img);
end main;

执行结果:

[...]\obj\main.exe
 0

预期结果应为1天,实际得到0天,原因及解决方法如下:

原因分析

这是夏令时切换导致的问题。2011年3月27日,欧洲多数地区(如中欧时区)执行夏令时切换,时钟被向前拨1小时——当天的23:00结束后,直接进入次日的01:00,不存在3月28日00:00这个时间点。

Ada.Calendar的Time_Of函数默认基于本地时区生成时间,当你尝试创建3月28日00:00这个不存在的时间时,系统会自动将其调整为3月28日01:00。而3月27日00:00到3月28日01:00的时间间隔为23小时,Day_Count类型仅统计完整的24小时周期,23小时不足1天,因此结果为0。

解决方法

方法1:使用Difference函数精确计算

Ada.Calendar.Arithmetic包中的Difference函数能正确处理夏令时带来的时间调整,精确拆分天数和剩余秒数:

with Ada.Calendar;            use Ada.Calendar;
with Ada.Calendar.Arithmetic; use Ada.Calendar.Arithmetic;
with Ada.Text_IO;             use Ada.Text_IO;
procedure main is
   t0 : Time      := Time_Of (Year => 2_011, Month => 3, Day => 27);
   t1 : Time      := Time_Of (Year => 2_011, Month => 3, Day => 28);
   da : Day_Count;
   sec : Day_Duration;
begin
   Difference (Left => t1, Right => t0, Days => da, Seconds => sec);
   Put_Line ("天数差: " & da'Img & ", 剩余秒数: " & sec'Img);
end main;

执行后会得到正确的天数差1,剩余秒数3600(即1小时),符合实际时间间隔。

方法2:基于UTC时间计算

UTC时区不存在夏令时切换,直接使用UTC时间计算可避免这类问题:

with Ada.Calendar;            use Ada.Calendar;
with Ada.Calendar.Arithmetic; use Ada.Calendar.Arithmetic;
with Ada.Text_IO;             use Ada.Text_IO;
with Ada.Calendar.Time_Zones; use Ada.Calendar.Time_Zones;
procedure main is
   t0 : Time      := Time_Of (Year => 2_011, Month => 3, Day => 27,
                              Time_Zone => UTC_Time_Zone);
   t1 : Time      := Time_Of (Year => 2_011, Month => 3, Day => 28,
                              Time_Zone => UTC_Time_Zone);
   da : Day_Count := t1 - t0;
begin
   Put_Line (da'Img);
end main;

这段代码的执行结果会直接返回1,完全符合预期。

内容的提问来源于stack exchange,提问作者Roland Coghetto

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.28 15:46:25