표준 라이브러리: 날짜와 시간
표준 라이브러리: 날짜와 시간 (Standard library: Dates & Times)
표준 라이브러리는 두 가지 접근 방식을 사용해 날짜와 시간 처리를 지원해요:
- 캘린더(Calendar) 접근 방식 — 일반적으로 날짜와 시간을 다루기에 적합해요
- 실시간(Real-time) 접근 방식 — 향상된 정밀도가 필요한 실시간 애플리케이션에 더 적합해요 (예: 절대 클록에 접근하고 시간 간격을 처리). 이 접근 방식은 시간만 지원하고 날짜는 지원하지 않는다는 점에 주의하세요.
다음 절들에서 이 두 접근 방식을 제시할게요.
본문
날짜와 시간 처리 (Date and time handling)
Ada.Calendar 패키지는 날짜와 시간 처리를 지원해요. 간단한 예시를 볼게요:
with Ada.Text_IO; use Ada.Text_IO;
with Ada.Calendar; use Ada.Calendar;
with Ada.Calendar.Formatting;
use Ada.Calendar.Formatting;
procedure Display_Current_Time is
Now : Time := Clock;
begin
Put_Line ("Current time: " & Image (Now));
end Display_Current_Time;
이 예시는 Clock 함수 호출로 검색한 현재 날짜와 시간을 표시해요. Ada.Calendar.Formatting 패키지의 Image 함수를 호출해 현재 날짜와 시간에 대한 String을 얻어요. 대신 Split 함수를 사용해 각 구성 요소를 검색할 수도 있어요. 예를 들어:
with Ada.Text_IO; use Ada.Text_IO;
with Ada.Calendar; use Ada.Calendar;
procedure Display_Current_Year is
Now : Time := Clock;
Now_Year : Year_Number;
Now_Month : Month_Number;
Now_Day : Day_Number;
Now_Seconds : Day_Duration;
begin
Split (Now,
Now_Year,
Now_Month,
Now_Day,
Now_Seconds);
Put_Line ("Current year is: "
& Year_Number'Image (Now_Year));
Put_Line ("Current month is: "
& Month_Number'Image (Now_Month));
Put_Line ("Current day is: "
& Day_Number'Image (Now_Day));
end Display_Current_Year;
여기서 각 요소를 검색해 개별적으로 표시해요.
날짜로 지연 (Delaying using date)
특정 날짜와 시간에 재시작되도록 애플리케이션을 지연시킬 수 있어요. 태스킹 챕터에서 비슷한 것을 봤었어요. delay until 문으로 이걸 해요. 예를 들어:
with Ada.Text_IO; use Ada.Text_IO;
with Ada.Calendar; use Ada.Calendar;
with Ada.Calendar.Formatting;
use Ada.Calendar.Formatting;
with Ada.Calendar.Time_Zones;
use Ada.Calendar.Time_Zones;
procedure Display_Delay_Next_Specific_Time is
TZ : Time_Offset := UTC_Time_Offset;
Next : Time :=
Ada.Calendar.Formatting.Time_Of
(Year => 2018,
Month => 5,
Day => 1,
Hour => 15,
Minute => 0,
Second => 0,
Sub_Second => 0.0,
Leap_Second => False,
Time_Zone => TZ);
-- Next = 2018-05-01 15:00:00.00
-- (현지 시간대)
begin
Put_Line ("Let's wait until...");
Put_Line (Image (Next, True, TZ));
delay until Next;
Put_Line ("Enough waiting!");
end Display_Delay_Next_Specific_Time;
이 예시에서 날짜의 다양한 구성 요소(년, 월 등)를 받아 Time 타입의 요소를 반환하는 Time_Of 호출로 Next를 초기화해 날짜와 시간을 지정해요. 지정된 날짜가 과거이므로 delay until 문은 눈에 띄는 효과를 내지 못해요. 하지만 미래의 날짜를 전달하면 프로그램은 그 특정 날짜와 시간이 도착할 때까지 기다려요.
여기서 시간을 현지 시간대로 변환해요. 시간대를 지정하지 않으면 기본적으로 협정 세계시(Coordinated Universal Time) (UTC로 약칭)가 사용돼요. Ada.Calendar.Time_Zones 패키지의 UTC_Time_Offset 호출로 UTC에 대한 시간 오프셋을 검색해 TZ를 초기화하고 Time_Of 호출에서 사용할 수 있어요. Time_Of에 제공된 정보를 현지 시간대 기준으로 만들려면 이 정도면 충분해요.
Next를 String으로 초기화해 비슷한 결과를 얻을 수도 있어요. Ada.Calendar.Formatting 패키지의 Value 호출로 이걸 할 수 있어요. 수정된 코드는 다음과 같아요:
with Ada.Text_IO; use Ada.Text_IO;
with Ada.Calendar; use Ada.Calendar;
with Ada.Calendar.Formatting;
use Ada.Calendar.Formatting;
with Ada.Calendar.Time_Zones;
use Ada.Calendar.Time_Zones;
procedure Display_Delay_Next_Specific_Time is
TZ : Time_Offset := UTC_Time_Offset;
Next : Time :=
Ada.Calendar.Formatting.Value
("2018-05-01 15:00:00.00", TZ);
-- Next = 2018-05-01 15:00:00.00
-- (현지 시간대)
begin
Put_Line ("Let's wait until...");
Put_Line (Image (Next, True, TZ));
delay until Next;
Put_Line ("Enough waiting!");
end Display_Delay_Next_Specific_Time;
이 예시에서도 Value 호출의 TZ를 사용해 입력 시간을 현재 시간대로 조정해요.
위 예시들에서는 특정 날짜와 시간으로 지연했어요. 태스킹 챕터에서 봤듯이 현재 시간을 기준으로 지연을 지정할 수도 있어요. 예를 들어 현재 시간을 사용해 5초를 지연시킬 수 있어요:
with Ada.Calendar; use Ada.Calendar;
with Ada.Text_IO; use Ada.Text_IO;
procedure Display_Delay_Next is
D : Duration := 5.0;
-- ^ 초
Now : Time := Clock;
Next : Time := Now + D;
-- ^ 다음 시점을
-- 지정하는 데
-- duration 사용
begin
Put_Line ("Let's wait "
& Duration'Image (D)
& " seconds...");
delay until Next;
Put_Line ("Enough waiting!");
end Display_Delay_Next;
여기서 D에 5초의 시간을 지정하고, Now의 현재 시간에 더해 그 합을 Next에 저장해요. 그런 다음 delay until 문에서 사용해요.
실시간 (Real-time)
Ada.Calendar 외에도 표준 라이브러리는 실시간 애플리케이션을 위한 시간 연산을 지원해요. 이는 Ada.Real_Time 패키지에 포함돼 있어요. 이 패키지에도 Time 타입이 있어요. 하지만 Ada.Real_Time 패키지에서 Time 타입은 절대 클록을 나타내고 시간 간격을 다루는 데 사용돼요. 이는 날짜와 시간을 나타내는 데 Time 타입을 사용하는 Ada.Calendar와 대조돼요.
이전 절에서 Ada.Calendar의 Time 타입과 delay until 문을 사용해 애플리케이션을 5초 지연했었어요. 대신 Ada.Real_Time 패키지를 사용할 수도 있었어요. 그 예시를 수정해 볼게요:
with Ada.Text_IO; use Ada.Text_IO;
with Ada.Real_Time; use Ada.Real_Time;
procedure Display_Delay_Next_Real_Time is
D : Time_Span := Seconds (5);
Next : Time := Clock + D;
begin
Put_Line ("Let's wait "
& Duration'Image (To_Duration (D))
& " seconds...");
delay until Next;
Put_Line ("Enough waiting!");
end Display_Delay_Next_Real_Time;
주요 차이점은 D가 이제 Ada.Real_Time 패키지에 정의된 Time_Span 타입의 변수라는 것이에요. Seconds 함수를 호출해 D를 초기화하는데, 대신 Nanoseconds를 호출하면 더 미세한 단위를 얻을 수 있었어요. 또한 표시하기 전에 To_Duration으로 D를 Duration 타입으로 변환해야 해요.
벤치마킹 (Benchmarking)
Ada.Real_Time 패키지를 사용하는 흥미로운 응용은 벤치마킹이에요. 태스킹을 논의할 때 이전 절에서 그 패키지를 사용한 적이 있어요. 벤치마킹 예시를 볼게요:
with Ada.Text_IO; use Ada.Text_IO;
with Ada.Real_Time; use Ada.Real_Time;
procedure Display_Benchmarking is
procedure Computational_Intensive_App is
begin
delay 5.0;
end Computational_Intensive_App;
Start_Time, Stop_Time : Time;
Elapsed_Time : Time_Span;
begin
Start_Time := Clock;
Computational_Intensive_App;
Stop_Time := Clock;
Elapsed_Time := Stop_Time - Start_Time;
Put_Line ("Elapsed time: "
& Duration'Image
(To_Duration (Elapsed_Time))
& " seconds");
end Display_Benchmarking;
이 예시는 간단한 delay 문으로 구현된 더미 Computational_Intensive_App을 정의해요. Start_Time과 Stop_Time을 당시 클록에서 초기화하고 경과 시간을 계산해요. 프로그램을 실행하면 시간이 대략 5초임을 알 수 있는데, 이는 delay 문 때문이에요.
유사한 응용은 CPU 시간 벤치마킹이에요. Execution_Time 패키지를 사용해 구현할 수 있어요. CPU 시간을 측정하도록 이전 예시를 수정해 볼게요:
with Ada.Text_IO; use Ada.Text_IO;
with Ada.Real_Time; use Ada.Real_Time;
with Ada.Execution_Time; use Ada.Execution_Time;
procedure Display_Benchmarking_CPU_Time is
procedure Computational_Intensive_App is
begin
delay 5.0;
end Computational_Intensive_App;
Start_Time, Stop_Time : CPU_Time;
Elapsed_Time : Time_Span;
begin
Start_Time := Clock;
Computational_Intensive_App;
Stop_Time := Clock;
Elapsed_Time := Stop_Time - Start_Time;
Put_Line ("CPU time: "
& Duration'Image
(To_Duration (Elapsed_Time))
& " seconds");
end Display_Benchmarking_CPU_Time;
이 예시에서 Start_Time과 Stop_Time은 Time 대신 CPU_Time 타입이에요. 하지만 두 변수를 초기화하고 경과 시간을 계산하는 데는 여전히 Clock 함수를 호출해요. 프로그램을 실행하면 CPU 시간이 이전에 본 5초보다 상당히 낮다는 것을 알 수 있어요. delay 문이 많은 CPU 시간을 요구하지 않기 때문이에요. Computational_Intensive_App의 구현을 긴 루프의 수학 함수를 사용하도록 바꾸면 결과가 달라져요. 예를 들어:
with Ada.Text_IO; use Ada.Text_IO;
with Ada.Real_Time; use Ada.Real_Time;
with Ada.Execution_Time; use Ada.Execution_Time;
with Ada.Numerics.Generic_Elementary_Functions;
procedure Display_Benchmarking_Math is
procedure Computational_Intensive_App is
package Funcs is new
Ada.Numerics.Generic_Elementary_Functions
(Float_Type => Long_Long_Float);
use Funcs;
X : Long_Long_Float;
begin
for I in 0 .. 1_000_000 loop
X := Tan (Arctan
(Tan (Arctan
(Tan (Arctan
(Tan (Arctan
(Tan (Arctan
(Tan (Arctan
(0.577))))))))))));
end loop;
end Computational_Intensive_App;
procedure Benchm_Elapsed_Time is
Start_Time, Stop_Time : Time;
Elapsed_Time : Time_Span;
begin
Start_Time := Clock;
Computational_Intensive_App;
Stop_Time := Clock;
Elapsed_Time := Stop_Time - Start_Time;
Put_Line ("Elapsed time: "
& Duration'Image
(To_Duration (Elapsed_Time))
& " seconds");
end Benchm_Elapsed_Time;
procedure Benchm_CPU_Time is
Start_Time, Stop_Time : CPU_Time;
Elapsed_Time : Time_Span;
begin
Start_Time := Clock;
Computational_Intensive_App;
Stop_Time := Clock;
Elapsed_Time := Stop_Time - Start_Time;
Put_Line ("CPU time: "
& Duration'Image
(To_Duration (Elapsed_Time))
& " seconds");
end Benchm_CPU_Time;
begin
Benchm_Elapsed_Time;
Benchm_CPU_Time;
end Display_Benchmarking_Math;
이제 더미 Computational_Intensive_App이 상당한 CPU 시간을 요구하는 수학 연산을 포함하므로, 측정된 경과 시간과 CPU 시간이 이전보다 훨씬 더 가까워져요.