Тематика этой главы инициирована той
Работа с календарными датами
Тематика этой главы инициирована той бурной компанией по поводу проблемы 2000 года (на Западе она более известна под аббревиатурой Y2K), которая была развернута в средствах массовой информации не без поддержки со стороны наиболее крупных производителей компьютеров и программного обеспечения. Несмотря на то, что проблема была чрезмерно раздута, элементарная безграмотность производителей компьютерных программ уже в 2000 году нанесла серьезный урон ряду банков Японии. Они не учли, что наступивший год был високосным, и многие банковские операции 29 февраля не состоялись. Мы надеемся, что материал настоящей главы поможет нашим читателям при разработке правильных программ, связанных с учетом временных интервалов.
Немного истории
Термин "календарь" обязан своим происхождением латинским словам calendae ("первый день месяца") и calendarium ("долговая книга"). В Древнем Риме на первое число каждого месяца приходилось время уплаты процентов по долгам.
Наиболее стабильным длительным промежутком времени с точки зрения ученых, ведущих астрономические наблюдения, является тропический год — интервал между моментами прохождения центра солнца через так называемую точку весеннего или осеннего равноденствия. Наблюдается это явление 21 марта и 23 сентября в обычный год и со смещением на один день — в високосный год. В этот момент лучи солнца падают на экватор отвесно и продолжительности ночи и дня совпадают. Длительность тропического года составляет 365 суток 5 часов 48 минут и примерно 46 секунд (365,2422 солнечных суток, длительность последних — 24 часа).
Древние календари, в большинстве своем, базировались на фазах Луны. Так, например, в Вавилоне год состоял из 12 лунных месяцев с чередующейся длительностью месяцев 29->30->29->30-> ... . Однако суммарная длительность такого года составляла 354 дня.
Один из первых солнечных календарей был принят в Египте примерно в IV в. до н. э. По египетскому календарю год состоял из 365 дней и включал 12 месяцев по 30 дней. В конце года 5 дней объявлялись праздничными и не входили ни в один из месяцев.
Наиболее близким к тропическому году стал римский календарь, принятый по указу императора Юлия Цезаря в 47 г. до н. э. Для ликвидации разницы с астрономическим годом длительность 46-го года была установлена в 432 дня. После этого вводились 3 обычных года по 365 дней, за которыми следовал 1 високосный год. Таким образом, средняя продолжительность римского года достигла 365,25 суток, что немного превышало длительность тропического года.
Тем не менее за 1500 лет набежало порядка 10 лишних суток. За очередное улучшение календаря принялся ватиканский ученый Луиджи Лилио. В 1582 году по указу папы Григория XIII был принят новый календарь, переход на который в разных странах растянулся на 200—300 лет. В России, например, новый календарь был введен декретом СНК РСФСР в январе 1918 года (после 31 января наступило 14 февраля, день недели при этом сохранился автоматически). Даты римского календаря стали называть "старым стилем", а даты григорианского календаря — "новым стилем". Суть ватиканской реформы заключалась в следующем. После четверга 4 октября 1582 года следующим днем объявлялась пятница 15 октября. Так устранялись набежавшие излишки. Второе новшество заключалось в том, что из круглых дат столетий исключались високосные годы, которые не делились нацело на 400. При этом средняя длительность года по григорианскому календарю оказалась больше тропического года всего на 26 с. Так что, разница в 1 сутки сможет набежать примерно к 4860 году.
Обратите внимание на специфику перехода от летоисчисления до новой эры. Первый год новой эры (эры Дионисия), последовавший после первого года до новой эры, отсчитывается от даты рождества Христова. С точки зрения математики, ему должен предшествовать нулевой год, которого не было. Поэтому в алгоритмах исчисления непрерывных календарных дат номера лет до новой эры следует считать отрицательными и увеличивать их на 1.
В конце того же XVI века астроном Джозеф Скалигер предложил новый способ отсчета времени. Начинался он от некоторого условного нуля (12 часов дня всемирного времени в понедельник 1 января 4713 года до новой эры, а с учетом приведенного выше замечания начальный год равен —4712) и представлялся в виде постоянно работающего таймера, отсчитывающего сутки и текущее время. Целая часть Юлианской даты JD (она была так названа в честь отца Скалигера) определяла количество суток, прошедших от начала отсчета, а дробная часть от 0,0 до 0,99999 соответствовала показанию суточных часов. Переход к следующей единице отсчета происходил в 12 часов очередного дня.
Например:
1 января 4712 г. до н.э. в 12 часов дня JD = 0.00000
2 января 4712 г. до н.э. в 12 часов дня JD = 1.00000
3 января 4712 г. до н.э. в 18 часов вечера JD = 2.25000
1 января 1900 г. в 12 часов дня JD = 2415021.0
22 июня 1941 г. в 4 часа утра JD = 2430167.66667
9 мая 1945 г. в 12 часов дня JD = 2431585.0
1 января 1999 г. в 12 часов дня JD = 2451180.0
1 января 2000 г. в 12 часов дня JD = 2451545.0
Следует заметить, что предложенная идея отсчета времени используется не только астрономами. В системах визуального программирования Borland C++ Builder и Delphi появился класс данных типа TDateTime, в объектах которого хранится обобщенное значение даты и времени в формате вещественного числа с двойной точностью (double). Его целая часть равна количеству дней, прошедших с полуночи 30 декабря 1899 года, а дробная часть соответствует времени дня. По сравнению с юлианской датой изменилась только точка начала отсчета.
Хранение даты и времени в формате юлианского дня представляется достаточно экономичным. Потребуется всего 8 байт для величины типа double, тогда как для запоминания символьной строки вида "YYYY/MM/DD HH:MM:SS" необходимо не менее 20 байт. Если нужно хранить только целую часть JD (тип long), то можно ограничиться 4 байтами. Конечно, для запоминания даты и времени в числовом машинном формате можно обойтись и 7 байтами (2 байта под год и по 1 байту под остальные компоненты). В некоторых системных программах MS-DOS попытки упаковать дату привели к еще более сжатым форматам. Вместо года Y хранится двоичное число, равное Y-1980 и принадлежащее интервалу [0,119], на номер месяца отведено 4 бита, а на все остальные компоненты — по 5 бит. Это позволило втиснуть дату и время в 32 двоичных разряда. Однако вместо полного номера года так можно представить только его младшие цифры, а вместо полного числа секунд — количество полусекунд. Для хранения дат создания файлов такой способ вполне пригоден, но для программ обработки календарных дат из более широкого временного интервала явно не годится.
Непрерывный таймер Дж. Скалигера удобен еще и тем, что позволяет очень просто вычислять различные временные интервалы как с точностью до суток, прошедших между двумя календарными датами, так и с точностью до секунд и даже долей секунды. В дальнейшем мы покажем, что по JD вычислить день недели можно всего за две операции.
Сложность заключается только в одном — надо перевести дату и время дня в показания юлианского хронометра. Первые алгоритмы такого перевода, которыми пользовались астрономы, базировались на таблицах юлианских дат, приходящихся на начало года. Дальше оставалось подсчитать порядковый день в году, соответствующий преобразуемой дате, и выполнить сложение. Однако для компьютерных программ табличный алгоритм неудобен, т. к. он связан с хранением довольно больших массивов, которые ежегодно приходилось пополнять.
Вычисление юлианских дат
Существует довольно много алгоритмов преобразования григорианских дат в юлианские, не использующих таблицы. Мы остановимся на трех из них. Алгоритм JDI впервые был опубликован на алгоритмическом языке АЛГОЛ-60 в журнале американской ассоциации вычислительных машин (Fliegel H. F., Van Flandern Т. С. A Machine Algorithm for Processing Calender Dates (algorithm 657). Communications of the ACM, 1968). Позднее он был переведен на ФОРТРАН (Spaeth H. Ausgewaehlte Operations Research-Algorithmen in FORTRAN. Wien, 1975) и послужил прообразом нашей функции JDI. Неформальное описание алгоритма JD2, ориентированное на использование ручных калькуляторов, приводится в книге Ж. Меёса "Астрономические формулы для калькуляторов" (М.: Мир, 1988). Наконец, алгоритм аоз описан в предисловии редактора перевода книги Меёса. Основным недостатком указанных публикаций является отсутствие информации о допустимом временном интервале, на котором тот или иной алгоритм работает правильно. Для определения таких интервалов нам пришлось провести довольно громоздкий вычислительный эксперимент.
Алгоритм JD1
Функция JDI предназначена для вычисления юлианской даты по году (Y), номеру месяца (м) и номеру дня месяца (о) на 12 часов полудня. Вместо неформального описания алгоритма JDI ниже приводится текст соответствующей функции JDI.C, содержащей всего три строки. При переводе фортрановской программы потребовалась аккуратность с явным заданием типа промежуточных данных и некоторых констант.
long JDI(int Y,int M,int D) {
long q,j;
j=(M-14)/12;
q=Y+j+4800;
return D-32075L+1461*q/4+367L*(M-2-12*j)/12-3*((q+100)/100) /4; }
Численный эксперимент показал, что формулы алгоритма JDI справедливы только для дат позднее 15.10.1582. В соответствующих оригинальных публикациях это ограничение не приводится. Возможно, что на практике большинству из нас и не придется обрабатывать более ранние даты, однако оговорка о сфере применимости алгоритма представляется нам обязательной.
Алгоритм JD2
Пусть григорианская дата представлена в виде двух целых чисел у (номер года, который может быть как положительным, так и отрицательным для дат до но-
вой эры), м (номер месяца — число от 1 до 12) и вещественного числа от = D.T (D — номер дня в месяце, т — часть текущего дня от 0,00000 до 0,99999, прошедшая от полуночи). Единственная тонкость в формулах Меёса заключается в том, что используемая им функция int означает выделение целой части без какого-либо округления в большую или меньшую сторону.
Если м > 2, то положим y = Y и m = M, в противном случае у = Y - 1 и m = м + 12. Если григорианская дата приходится на момент после 15.10.1582, то вычисляются:
А = int(у/100)
В = 2 - А + int(А/4)
Если заданная дата предшествует моменту принятия григорианского календаря, то следует положить в = о. Для правильной обработки отрицательных номеров года следует вычислить:
С = int(365.25*у) при у > 0
С = int(365.25 * у - 0.75) При у < 0
Окончательная формула для нахождения JD имеет вид:
JD = С + int (30. 6001 * (m+D) + DT + 1720994.5 + В
Численные эксперименты показали, что функция JD2 выдает правильные результаты на всем интервале дат, начиная с 1.01.4713 до н. э. (то есть от Y = -4712, м = 1, от = 1.5) и до наших дней. Ее работа была проверена нами в цикле для 12 часов полудня каждого дня начального года. А затем — также в цикле по первому дню каждого последующего года с учетом смены обычных и високосных лет.
Алгоритм JD3
Алгоритм JD3, указанный в предисловии редактором перевода книги Меёса, привлекает своей простотой. В нем нет никаких логических проверок и реализующая его функция на языке Си имеет вид:
double JD3(int Y,int M,double DT) {
return 367.0*Y-floor(7.0*(Y+floor((M+9.)/12.))/4.)+
floor(275.0*M/9.)+DT+1721013.5; }
Однако первый же эксперимент с вычислением даты JD, приходящейся на 101,1600 (JD3 = 2305445.0), привел к расхождению с результатом Меёса (JD2 = = 2305448.0) на 3 дня. Более тщательный эксперимент показал, что функция JD3 начинает выдавать правильные результаты с 1.03.1900. А заключительной датой, до которой значения JD3 совпадают с JD2, является 29.02.2100.
Составить функцию JD, вычисляющую юлианскую
Задание 9.01. Вычисления юлианских дат
Составить функцию JD, вычисляющую юлианскую дату по году (Y), номеру месяца (м), номеру дня и значению времени, заданным в виде вещественного числа от (целая часть от — порядковый номер дня в месяце, дробная часть от — часть суток, прошедшая после полуночи). Проверки на правильность задания исходной информации исключены, чтобы не загромождать текст программы.
Совет 1 (общий)
По результатам довольно обширного численного эксперимента мы выяснили, что наиболее точный алгоритм представлен формулами Меёса. Поэтому тексты приводимых ниже программ используют алгоритм JD2. Если ваши задачи относятся к более узким временным интервалам, то текст функции JD можно заменить, используя один из выше описанных алгоритмов.
Программа 9_01.bas
DECLARE FUNCTION JD! (Y%, M%, DT!)
REM Перевод даты григорианского календаря
REM в юлианскую дату (алгоритм Меёса)
CLS
INPUT "Задайте год григорианского календаря : ",Y%
INPUT "Задайте месяц григорианского календаря : ",М%
INPUT "Задайте день и время : ",DT
PRINT USING "##### ### ###.#";Y%;M%;DT;
jdl=JD(Y%,M%,DT)
PRINT USING " JD =#########.#####";jdl
END
FUNCTION JD(Y%,M%,DT)
' Y - григорианский год [-4713,9999]
' М - григорианский месяц [1,12]
' целая часть DT - день [1,31]
' дробная часть DT - время, прошедшее
' от начала текущего дня [.0,.99999]
' Возвращаемое значение - юлианская дата
' Целая часть JD - число дней, прошедших
' от 1 января 4713 года до новой эры
' Дробная часть JD - время, прошедшее
' после 12 часов полудня дня JD
b%=0: yy%=Y%: mm%=M%
IF M%<3 THEN уу%=уу%-1: mm%=mm%+12
а%=уу% \ 100
IF Y%+M% / 1001+DT/10000 > 1582.10151 THEN
b%=b%+2-a%+(a% \ 4} END IF
c&=INT(365.25*yy%)
IF yy%<0 THEN c&=INT(365.25*yy%-.75)
JD=c&+INT(30.6001*(mm%+l))+DT+1720994.5#+b%
END FUNCTION
Программа 9_01.с
#include <stdio.h>
#include <conio.h>
#include <math.h>
double JD (int Y,int M,double DT);
main() {
int Y,M,day;
double DT,jd;
clrscr();
printf("\ n Задайте год григорианского календаря : ");
scanf("%d",&Y);
printf("\n Задайте месяц григорианского календаря : ");
scanf("%d",SM);
printf("\n Задайте день и время : ");
scanf("%lf",&DT);
jd=JD(Y,M,DT);
printf("\n JD =%15.5f",jd);
getch();
}
/*----------------------------------------* /
/*----------------------------------------* /
double JD(int Y,int M,double DT)
/*******************************************/
/* Перевод даты григорианского календаря */
/* в юлианскую дату (алгоритм Меёса) */
/* Y - григорианский год [-4713,9999] */
/* М - григорианский месяц [1,12] */
/* целая часть DT - день [1,31] */
/* дробная часть DT - время, прошедшее */
/* от начала текущего дня [.0,.99999] */
/* Возвращаемое значение - юлианская дата */
/* Целая часть JD - число дней, прошедших */
/* от 1 января 4713 года до новой эры */
/* Дробная часть JD - время, прошедшее */
/* после 12 часов полудня дня JD */
{
int a,b=0,m,y;
long с;
y=Y;
m=M;
if (M<3) { y--; m += 12; }
a=y/100;
if(Y+M/100.+DT/10000 > 1582.1015)
b += 2-a+(int)(a/4.);
c=365.25*y;
if(y<0)c=365.25*y-0.75;
return c+(long)(30.6001*(m+1))+DT+1720994.5+b; }
Программа 9_01.pas
program gd_t6_jd;
uses Crt;
var
Y,M,day:integer; DT,jdl:double;
function JD(Y,M:integer;DT:double):double;
{ Перевод даты григорианского календаря }
{ в юлианскую дату (алгоритм Меёса) }
{ Y - григорианский год [-4713,9999] }
{ М - григорианский месяц [1,12] }
{ целая часть DT - день [1,31] }
{ дробная часть DT - время, прошедшее }
{ от начала текущего дня [.0,.99999] }
{ Возвращаемое значение - юлианская дата }
{ Целая часть JD - число дней, прошедших }
( от 1 января 4713 года до новой эры }
{ Дробная часть JD - время, прошедшее }
{ после 12 часов полудня дня JD }
var
a,b,mm,yy:integer;
с:longint; begin
b:=0;
yy:=Y;
mm:=M;
if M<3 then begin yy:=yy-l;
mm:=mm+12;
end;
a:=yy div 100;
if (Y+M/100.+DT/10000)>1582.1015 then b:=b+2-a+(a div 4);
c:=trunc(365.25*yy);
if yy<0 then c:=trunc(365.25*yy-0.75) ;
JD:=c+trunc(30.6001*(mm+1))+DT+1720994.5+b;
end;
begin
clrscr;
write('Задайте год григорианского календаря : ');
readln(Y);
write('Задайте месяц григорианского календаря : ');
readln(M);
write('Задайте день и время : ');
readln(DT);
write(Y:4,M:3, ' ',DT:3:1);
jdl:=JD(Y,M,DT);
writelnC JD =', jdl:15:5) ;
readln; end.
Задание 9.02. Вычисление дат григорианского календаря
Составить подпрограмму GD, вычисляющую дату григорианского календаря по юлианской дате, представленной вещественным числом JD.
Совет 1 (общий)
Учитывая высокое качество алгоритмов Меёса, воспользуемся его же алгоритмом для обратного преобразования дат. Мы тщательно проверили его на большом количестве прямых и обратных преобразований григорианских и юлианских дат. В приведенных ниже формулах сохранены обозначения Меёса.
Вычислим JD+0.5 и обозначим через z целую часть, а через F — дробную. Если z > 2299161, то вычислим:
a=int((Z-1867216.25)/36524.25) A=Z+l+a-int(a/4) при z < 2299161 положим
A=Z
В=А+1524
C=int((B-122.1)/365.25
D=int(365.25*C)
E=int((B-D)/30.6001)
DT=B-D-int(30.6001*E) Номер месяца
M=Е-1, если E<13.5
M=Е-13,если Е>13.5 Номер года
Y=C-4716,если м>2.5
Y=C-4715,если М<2.5
Программа 9_02.bas
DECLARE SUB GD(jd!,y%,m%,DT!)
REM Преобразование юлианской даты JD в дату григорианского
КЕМ календаря - Y (год), М (месяц),
REM DT (день и часть времени, прошедшую от начала суток
CLS
INPUT "Задайте юлианскую дату : ",jd
GD jd,y%,m%,DT
PRINT USING "год = ##### месяц = ## день и время = ####";y%;m%;DT
END
SUB GD(jd,y%,m%,DT)
' Восстановление даты григорианского календаря
' по юлианской дате jd. Результаты заносятся в
' у% - год
' m% - месяц
' dt - день (целая часть) и время дня (дробная часть)
DIM A AS LONG, В AS LONG, С AS LONG, D AS LONG, Z AS LONG
DIM aa AS LONG, E AS INTEGER, F AS DOUBLE
Z=INT(jd+.5)
F=jd+.5-Z
A=Z
IF Z>=2299161 THEN
aa=INT((Z-1867216.25#)/36524.25) A=A+l+aa-(aa\4)
END IF B=A+1524
C=INT((B-122.1)/365.25) D=INT(365.25*C) E=INT((B-D)/30.6001)
DT=B-D-INT(30.6001*E)+F
IF E<13.5 THEN m%=E-l
ELSE m%=E-13
IF m%>2.5 THEN y%=C-4716
ELSE y%=C-4715
END SUB
Программа 9_02.с
#include <stdio.h>
#include <conio.h>
void GD(double jd,int *y,int *m,double *dt);
main () (
int Y,M;
double DT,jd;
clrscr () ;
printf("\n Задайте юлианскую дату : ");
scanf("%lf",&jd);
GD(jd, &Y, &M, &DT) ;
printf("\n годl=%d месяц=%d день и время=%-15.51f",Y,M,DT);
getch();
}
/*--------------------------------------*/
void GD(double jd,int *y,int *m,double *dt)
/* Восстановление даты григорианского */
/* календаря по юлианской дате jd */
/* у - год, m - месяц */
/* dt - день (целая часть) */
/* и время дня (дробная часть) */
/**************************************/
{
long a,A,B,C,D,E, Z;
double F;
Z=jd+0.5;
F=jd+0.5-Z; A=Z;
if(Z>=2299161)
{
a=(Z-1867216.25)/36524.25;
A += l+a-a/4; }
B=A+1524;
C=(B-122.1)/365.25;
D=365.25*C; E=(B-D)/30.6001;
*dt=B-D-(int)(30.6001*E)+F;
if(E<13.5) *m=E-l;
else *m=E-13;
if(*m>2.5) *y=C-4716;
else *y=C-4715; }
Программа 9_02.pas
program jd_to_gd;
{ Преобразование юлианской даты JD в дату григорианского календаря - Y (год), М (месяц), DT (день и часть времени, прошедшую от начала суток }
uses crt; var
Y,M:integer;
DT,jd:double;
procedure GD(jd:double;
var y,m:integer; var dtrdouble);
{ Восстановление даты григорианского }
{ календаря по юлианской дате jd }
{ у - год, m - месяц }
{ dt - день (целая часть) }
( и время дня (дробная часть) }
var
aa,A,B,C,D,E,Z:longint;
F:double; begin
Z:=trunc(jd+0.5);
F:=jd+0.5-Z;
A:=Z;
if Z>=2299161 then begin
aa:=trunc((Z-1867216.25)/36524.25);
A:=A+l+aa-(aa div 4);
end;
B:=A+1524;
C:=trunc( (B-122.D/365.25) ;
D:=trunc(365.25*C);
E:=trunc((B-D)/30.6001);
dt:=B-D-trunc(30.6001*E)+F;
if E<13.5 then m:=E-l
else m:=E-13;
if m>2.5 then y:=C-4716
else y:=C-4715;
end;
begin
clrscr;
write('Задайте юлианскую дату : ');
readln(jd);
GD(jd,Y,M,DT);
writeln('год = ',Y:4,' месяц = ',M:2,' день и время = ',DT:4:1);
readln; end.
Задание 9.03. Интервал времени между двумя датами
Составить функцию dif_time, вычисляющую интервал между двумя датами григорианского календаря.
Совет 1 (общий)
Преобразуйте даты григорианского календаря и найдите разницу между соответствующими юлианскими датами. Чтобы не выяснять, какая из дат является предшествующей, можно найти модуль разности.
Программа 9_03.bas
DECLARE FUNCTION JD! (Y%, M%, DT!)
DECLARE FUNCTION DifTime! (Yl%, Ml%, DTI!, Y2%, M2%, DT2!)
REM Определение интервала времени между двумя датами
REM григорианского календаря : (Y1,M1,DT1) и (Y2,M2,DT2)
CLS
INPUT "Задайте год григорианского календаря : ",Y1%
INPUT "Задайте месяц григорианского календаря : ",М1%
INPUT "Задайте день и время : ",DT1
INPUT "Задайте год григорианского календаря : ",Y2%
INPUT "Задайте месяц григорианского календаря : ",М2%
INPUT "Задайте день и время : ",DT2
PRINT "Интервал =",DifTime(Y1%,M1%,DTI,Y2%,M2%,DT2)
END
FUNCTION DifTime (Y1%,M1%,DTI,Y2%,M2%,DT2)
' Определение интервала времени между
' двумя григорианскими датами
' Y1,Y2 - годы М1,М2 - месяцы
' целые части DTI, DT2 - дни
' дробные части DTI, DT2 - время дня
jdl=JD(Y1%,M1%,DT1)
jd2=JD(Y2%,M2%,DT2)
DifTime=ABS(jdl-jd2) END FUNCTION
FUNCTION JD(Y%,M%,DT)
DIM a AS INTEGER, b AS INTEGER, mm AS INTEGER, yy AS INTEGER
DIM с AS LONG
b=0
yy=Y%
mm=M%
IF M%<3 THEN yy=yy-l: mm=mm+12
а=уу\100
IF Y%+M%/100!+DT/10000>1582.1015# THEN
b=b+2-a+a\4 END IF
c=INT(365.25*yy)
IF yy<0 THEN
c=INT(365.25*yy-.75)
JD=c+INT(30.6001*(iran+1))+DT+1720994.5#+b
END FUNCTION
Программа 9_03.с
#include <stdio.h>
#include <conio.h>
#include <math.h>
double dif_time(int Yl,int Ml,double DTI,
int Y2,int M2,double DT2);
double JD(int У,int M,double DT);
main () {
int Y1,Y2,M1,M2;
double DT1,DT2;
clrscr();
printf("\ n Задайте год григорианского календаря : ");
scanf("ld",&Yl);
printf("\n Задайте месяц григорианского календаря : ");
scanf("%d",&Ml);
printf("\nЗадайте день и время : ");
scanf("%lf",&DTD;
printf("\n Задайте год григорианского календаря : ");
scanf("%d",SY2);
printf("\n Задайте месяц григорианского календаря : ");
scanf("%d",&M2);
printf("\n Задайте день и время : "};
scanf("%lf",&DT2);
printf("\n Интервал = %lf",dif_time(Y1,M1,DTI,Y2,M2,DT2));
getch(); }
/*----------------------------*/
double dif_time(int Yl,int Ml,double DTI, int Y2,int M2, double DT2)
/* Определение интервала времени между */
/* двумя григорианскими датами */
/* Y1,Y2 - годы М1,М2 - месяцы */
/* целые части DTI, DT2 - дни */
/* дробные части DTI, DT2 - время дня */ /***************************************/
return fabs(JD(Yl,Ml,DTl)-JD(Y2,M2,DT2));
}
/*---------------------------------------------------* /
double JD(int Y,int M, double DT) {
int a,b=0,m,y;
long c;
y=Y;
m=M;
if (M<3) { y--; m += 12; }
a=y/100;
if(Y+M/100.+DT/10000 > 1582.1015)b += 2-a+(int)(a/4.);
c=365.25*y;
if(y<0) c=365.25*y-0.75;
return c+(long) (30.6001* (m+1))+DT+1720994.5+b; }
Программа 9_03.pas
program gd_to_jd;
{Определение интервала времени между двумя датами григорианского календаря : (Y1,M1,DT1) и (Y2,M2,DT2) }
uses Crt; var
Yl,Ml,Y2,М2:integer;
DTI,DT2:double;
function JD(Y,M:integer;
DT:double):double;
var
a,b,mm,yy:integer;
c:longint;
begin
b:=0;
yy:=Y;
mm:=M;
if M<3 then begin yy:=yy-l;
mm:=mm+12; end;
a:=yy div 100;
if (Y+M/100.+DT/10000)>1582.1015 then b:=b+2-a+(a div 4};
c:=trunc(365.25*yy);
if yy<0 then c:=trunc(365.25*yy-0.75);
JD:=c+trunc(30.6001*(mm+1))+DT+1720994.5+b;
end;
function dif_time(Yl,Ml:integer;
DTI:double;
Y2,M2:integer; DT2:double):double;
{ Определение интервала времени между }
{ двумя григорианскими датами }
{ Y1,Y2 - годы М1,М2 - месяда }
{ целые части DTI, DT2 - дни }
{ дробные части DTI, DT2 - время дня } begin
dif_time:=abs(JD(Y1,M1,DT1)-JD(Y2,M2,DT2)) ;
end;
begin
clrscr;
write(' Задайте год григорианского календаря : ');
readln(Yl);
write(' Задайте месяц григорианского календаря : ');
readln(Ml);
write(' Задайте день и время : ');
readln(DTl);
write(' Задайте год григорианского календаря : ');
readln(Y2);
write(' Задайте месяц григорианского календаря : ');
readln(M2);
write(' Задайте день и время : ') ; readln(DT2);
writeln('Интервал = ',dif_time(Y1,M1,DT1,Y2,M2, DT2):10:0); readln; end.
Задание 9.04. День недели
Составить функцию week_day, определяющую день недели по дате григорианского календаря.
Совет 1 (общий)
Преобразуйте григорианскую дату в юлианский день и воспользуйтесь довольно очевидной формулой:
день недели=(JD+1.5) mod 7
В ее справедливости нетрудно убедиться, вспомнив, что понедельник 1 января условной начальной точки отсчета универсального времени (год 4712 до н. э.) начинался в момент JD=-0 . 5. Приведенная выше формула дает 0 для воскресенья, 1 —для понедельника, 2 — для вторника, ..., 6 — для субботы.
Совет 2 (общий)
Функция week_dayl построена на базе аналогичной фортрановской программы, и сфера ее применения распространяется на даты позднее 15.10.1582.
Программа 9_04.bas
DECLARE FUNCTION JD!(Y%,M%,DT!)
DECLARE FUNCTION WeekDay!(Y%,M%,D%)
REM Определение дня недели
CLS
INPUT "Задайте год григорианского календаря : ",Y%
INPUT "Задайте месяц григорианского календаря : ",М%
INPUT "Задайте день : ",D%
PRINT "день недели = ";WeekDay(Y%, M%, D%)
END
FUNCTION JD(Y%,M%,DT)
DIM a AS INTEGER, b AS INTEGER, mm AS INTEGER, yy AS INTEGER
DIM с AS LONG
b=0
yy=Y%
mm=M%
IF M%<3 THEN yy=yy-l: mm=ram+12
a=yy\100
IF Y%+M%/100!+DT/10000>1582.1015# THEN
b=b+2-a+a\4 END IF
c=INT(365.25*yy)
IF yy<0 THEN c=INT(365.25*yy-.75)
JD=c+INT(30.6001*(mm+1))+DT+1720994.5#+b
END FUNCTION
FUNCTION WeekDay(Y%,M%,D%)
' Определение дня недели
' Y - григорианский год
' М - григорианский месяц (1 - 12)
' D - день (1 - 31)
' Возвращаемое значение :
' 0 - воскр., 1 - понед., 2 - вторник,...
WeekDay=INT(JD(Y%,M%,D%+1.5)) MOD 7
END FUNCTION
Программа 9_04.с
#include <stdio.h>
#include <conio.h>
#include <math.h>
int week_day(int Y,int M,int D);
double JD(int Y,int M,double DT);
main() {
int Y,M,D,day;
clrscr();
printf("\nЗадайте год григорианского календаря : ") ;
scanf("%d",&Y);
printf("\nЗадайте месяц григорианского календаря : ");
scanf("%d",&M);
printf("\nЗадайте день : ") ;
scanf("%d",&D);
day=week_day (Y, M, D) ,-
printf("\пдень недели = %d",day) ;
getch();
}
/*--------------------------------*/
int week_day(int У,int M,int D)
/* Вычисление дня недели */
/* Возвращаемое значение : */
/* 0 - воскр., 1 - понед., 2 - вторник,... */
/************************************/
{
return (long)(JD(Y,M,(double)D)+1.5) % 7;
}
/*---------------------------------*/
double JD(int Y,int M,double DT) int a,b=0,m,y;
long c;
y=Y;
m=M;
if (M<3) { y--; m += 12; }
a=y/100;
if(Y+M/100.+DT/10000 > 1582.1015) b += 2-a+(int)(a/4.);
c=365.25*y;
if(y<0)c=365.25*y-0.75;
return c+(long)(30.6001*(m+1))+DT+1720994.5+b; }
Функция week_day1.с
int week_dayl( int Y, int M, int D)
{
/********************************/
/* Вычисление дня недели */
/* Возвращаемые значения: */
/* 1 - пон., 2 - вторник,..., 7 -воскр */
int q,m;
q=M+10;
m=(M-14)/12+Y;
return ((13*(q-(q/13)*12)-1)/5+D+77+5* (m%100) /4 +
m/400-(m/100)*2)%7; }
Программа 9_04.pas
program WeekDay;
{ Определение дня недели }
uses Crt;
var
Y,M,D,day:integer;
function JD(Y,M:integer; DT:double):double; var
a,b,mm,yy:integer;
с:longint; begin
b:=0;
yy:=Y;
mm:=M;
if M<3 then begin yy:=yy-l;
mm:=mm+12; end;
a:=yy div 100;
if (Y+M/100.+DT/10000)>1582.1015 then b:=b+2-a+(a div 4);
c:=trunc(365.25*yy);
if yy<0 then c:=trunc(365.25*yy-0.75) ;
JD:=c+trunc(30.6001*(mm+l))+DT+1720994.5+b;
end;
function week_day(Y,M,D:integer):integer;
{ Определение дня недели }
{ Y - григорианский год }
{ М - григорианский месяц (1-12) }
{ D - день (1 - 31) }
{ Возвращаемое значение : }
{ 0 - воскр., 1 - понед., 2 - вторник,... }
begin
week_day:=trunc(JD(Y,M,D+1.5)) mod 7; end;
begin
clrscr;
write(' Задайте год григорианского календаря : ') ;
readln(Y);
write(' Задайте месяц григорианского календаря : ') ;
readln(M);
write (' Задайте день : ');
readln(D);
day:=week_day(Y,M,D);
writeln('день недели = ',day);
readln; end.
Задание 9.05. Порядковый день в году
Составить функцию dat_to_ord, вычисляющую порядковый номер дня в году по его дате.
Совет 1 (общий)
Воспользуемся алгоритмом, описанным в книге Меёса. Для обычного года:
N=int(275*M/9)-2*int((М+9)/12)+D-30
Для високосного года:
N=int(275*M/9)-int((М+9)/12)+D-30
Программа 9_05.bas
DECLARE FUNCTION DatToOrd!(y%,M%,D%)
REM Определение порядкового дня в году по
REM текущей дате (у - год, m -месяц, d - день)
CLS
INPUT "Задайте год : ",у%
INPUT "Задайте месяц : ",М%
INPUT "Задайте день : ",D%
PRINT "Порядковый номер дня в году = ";
DatToOrd(у%,M%,D%)
END
FUNCTION DatToOrd(y%,M%,D%)
DIM a1 AS INTEGER, a2 AS INTEGER
al=(M%+9)\12
a2=INT(275!*M%/9!}-a1+D%
IF (y% MOD 400=0) OR ( (y MOD 4=0) AND (y MOD 100<>0) ) THEN DatToOrd=a2-30
ELSE DatToOrd=a2-al-30
END IF
END FUNCTION
Программа 9_05.c
#include <stdio.h>
#include <conio.h>
int dat_to_ord(int y,int m,int d) ;
main() {
int Y,M,D;
clrscr();
printf("\nЗадайте год : ");
scanf("%d",&Y);
printf("\nЗадайте месяц : ");
scanf("%d",&M);
printf("\nЗадайте день : ");
scanf("%d",&D) ;:
printf("\nПорядковый номер дня в году = %d", dat_to_ord(Y,M,D));
getch();
}
/*-----------------------------------------*/
int dat_to_ord(int y,int m,int d)
{
int a1,a2;
al=(m+9.0)/12.0;
a2=(275.0*m/9.0)-a1+d-30;
if((y%400==0)||((y%4==0)&&(y%100!=0)))
return a2;
return a2-a1; }
Программа 9_05.pas
program ord day;
изез Crt; var
Y,M,D:integer;
function dat_to_ord(y,m,d:integer):integer; {
Определение порядкового дня в году по текущей дате (у - год, m - месяц, d - день) } var
al,a2:integer; begin
al:=(m+9) div 12;
a2:=trunc(275.0*m/9.0)-al+d-30;
if((y mod 400 = 0) OR {(y mod 4=0) AND (y mod 100 <>0))) then dat_to__ord: =a2
else dat_to_ord:=a2-al;
end;
begin
clrscr;
write('Задайте год : ');
readln(Y);
write('Задайте месяц : ');
readln(M);
write('Задайте день : ');
readln(D);
writeln('Порядковый номер дня в году = ', dat_to_ord(Y,M,D));
readln;
end.
Задание 9.06. Восстановление даты
Составить процедуру month_day, вычисляющую номера месяца (M) и дня (D) по порядковому номеру (N) дня в году.
Совет 1 (общий)
Воспользуемся алгоритмом, описанным в книге Меёса. Положим, что А = 1889 для обычного года и А = 1523—для високосного.
Вычислим :
B=int((N+A-122.1)/365.25)
C=N+A-int(365.25*B)
E=int(C/30.6001)
M=E-1 при Е<13.5
M=E-13 при Е>13.5
D=C-int(30.6001*E)
Программа 9_06.bas
DECLARE SUB MonthDay(Y%,OrdDay%,M%,D%)
RЕМ Восстановление даты по порядковому дню года
CLS
INPUT "Задайте год : ",Y%
INPUT "Задайте порядковый номер дня в году : ",OrdDay%
MonthDay Y%,OrdDay%,М%,D%
PRINT "Ему соответствует месяц = ",М%;" и день = ";D%
END
SUB MonthDay(Y%,OrdDay%,M%,D%)
' Восстановление месяца и дня в году Y%
' по порядковому номеру дня ord_day%
' М% - сюда засылается номер месяца
' D% - сюда засылается номер дня месяца
DIM A AS INTEGER, В AS INTEGER, С AS INTEGER, E AS INTEGER
A=1889
IF (Y% MOD 400=0)OR((Y% MOD 4=0)AND(Y% MOD l00<>0) ) THEN A=1523
B=INT((OrdDay%+A-122.1)/365.25)
C=OrdDay%+A-INT(365.25*B)
E=INT(C/30.6001)
IF E<13.5 THEN M%=E-1 ELSE M%=E-13'
D%=C-INT(30.6001*E)
END SUB
Программа 9_06.с
#include <stdio.h> ,
#include <conio.h>
#include <math.h>
void month_day(int Y,int ord_day,int *M,int *D);
main() {
int Y,M, D,ord_day;
clrscr();
printf("\n Задайте год : ");
scanf("%d",&Y);
printf("\n Задайте порядковый номер дня в году : ");
scanf("%d",&ord_day);
month_day(Y,ord_day,&M, &D);
printf("\nЕму соответствует месяц = %d и день = %d",M,D);
getch();
}
/*-------------------------------------*/
void month_day(int Y,int ord_day,int *M,int *D)
/*************************************/
/* Восстановление месяца и дня в году Y */
/* по порядковому номеру дня ord_day */
/* М - сюда засылается номер месяца */
/* D - сюда засылается номер дня месяца */
/****************************************/
{
int A=1889,B,C,E;
if((Y%400==0)||((Y%4==0)&&(Y%100!=0))) A=1523;
B=(ord_day+A-122.1)/365.25;
C=ord_da>y+A-floor (365. 25*B) ;
E=C/30.6001;
if(E<13.5) *M=E-1; else *M=E-13;
*D=C-floor(30.6001*E); }
Программа 9_06.pas
program ord_to_dat;
uses Crt;
var
Y,M,D,ord_day:integer;
procedure month_day(Y,ord_day:integer;var M,D:integer);
{ Восстановление месяца и дня в году Y }
{ по порядковому номеру дня ord_day }
{ М - сюда засылается номер месяца }
{ D - сюда засылается номер дня месяца } var
А,В, С,Е:integer; begin
А:=1889;
if(Y mod 400 = 0) OR ((Y mod 4 = 0)AND(Y mod 100 <>0))) then A:=1523;
B:=trunc((ord_day+A-122.1)/365.25) ;
C:=ord_day+A-trunc(365.25 * B);
E:=trunc(C/30.6001);
if(E<13.5) then M:=E-1 else M:=E-13;
D:=C-trunc(30.6001*E); end; begin
clrscr;
write('Задайте год : ');
readln(Y);
write ('Задайте порядковый номер дня в году : ');
readln(ord_day);
month_day(Y,ord_day,M,D);
writeln('Eмy соответствует месяц = ',М, ' и день = ',D);
readln; end.
Задание 9.07. Количество дней в месяце
Составить функцию max_day, определяющую количество дней по номеру месяца.
Совет 1 (общий)
Наверное, самый простой алгоритм основан на выборке нужного числа из предварительно подготовленного массива с учетом коррекции количества февральских дней в високосном году. Високосный год должен делиться без остатка на 400 или делиться на 4, но не делиться на 100.
Программа 9_07.bas
DECLARE FUNCTION MaxDay!(Y%,M%)
REM Определение количества дней в месяце
DATA 31,28,31,30,31,30,31,31,30,31,30,31
DIM SHARED DAYS(1 TO 12)
FOR J=l TO 12: READ DAYS(J): NEXT J
CLS
INPUT "Задайте год : ",Y%
INPUT "Задайте месяц : ",M%
PRINT "Число дней в этом месяце = ";
MaxDay (Y%,M%)
END
FUNCTION MaxDay(Y%,M%)
MaxDay=DAYS(M%)
IF M%<>2 THEN EXIT FUNCTION
IF (Y% MOD 400=0)OR((Y% MOD 4=0)AND(Y% MOD 100<>0) ) THEN MaxDay=29
END IF END FUNCTION
Программа 9_07.с
#include <stdio.h>
#include <conio.h>
int max_day(int Y, int M);
main() . {
int Y,M;
printf("\n Задайте год : ");
scanf("%d",&Y);
printf("\3адайте месяц : ");
scanf("%d",&M);
printf("\n Число дней в этом месяце = %d",max_day(Y,M));
getch();
}
/*--------------------------------------*/
int max_day(int Y, int M)
{ int days[]={31,28,31,30,31,31,30,31,30,31,30,31);
if(M != 2) return days[M-l];
if{(Y%400==0)||((Y%4==0)&&(Y%100!=0))}
return 29;
return 28; }
Программа 9_07.pas
program days_in_month;
{ Определение количества дней в месяце }
var
Y,M:integer;
function max_day(Y,M:integer):integer; const
days:array[1..12] of byte=(31,28,31,30,31,30, 31, 31, 30, 31, 30, 31);
begin
max_day:=days[M];
if(M<>2) then exit;
if((Y mod 400=0)OR((Y mod 4=0)AND(Y mod l00<>0) ) ) then
max_day:=29; end; begin
write('Задайте год : ');
readln(Y);
write('Задайте месяц : ');
readln(M);
writeln('Число дней в этом месяце = ',max_day(Y,M));
readln; end.
Задание 9.08. Календарь
Составить процедуру calendar, отображающую на экране дисплея календарь на заданный месяц любого года.
Совет 1 (общий)
Для понимания приведенных ниже программ достаточно разобраться с тремя моментами.
Во-первых, календарь любого месяца можно разместить в таблице, содержащей 7 строк (по числу дней недели) и 6 столбцов. В худшем варианте 1-е число
месяца выпадает на воскресенье, занимая тем самым последнюю клетку 1-го столбца, а два последних дня месяца — 30 и 31 — на понедельник и вторник последнего столбца. Двумерную таблицу календаря удобнее представить в виде одномерного массива из 42 элементов.
Во-вторых, для определения местоположения 1-го дня месяца мы можем обратиться к функции week_day.
Наконец, с помощью функции max_day мы можем определить число дней в заданном месяце. После этого остается очистить нулями массив из 42 элементов и расписать его с нужного места последовательными днями месяца. А затем отобразить на экране ненулевые элементы в соответствующих позициях экрана.
Программа 9_08.bas
DECLARE SUB calendar(Y%,M%)
DECLARE FUNCTION JD!(Y%,M%,DT!)
DECLARE FUNCTION WeekDay!(Y%,M%,D%)
DECLARE FUNCTION MaxDay!(Y%,M%)
REM Программа вывода календаря на любой месяц
DATA 31,28,31,30,31,30,31,31,30,31,30,31
DIM SHARED DAYS(1 TO 12)
FOR j=l TO 12: READ DAYS(j): NEXT j
CLS
INPUT "Задайте год : ",Y%
INPUT "Задайте месяц : ",M4
calendar Y%,M%
END
SUB calendar(Y%,M%)
DIM i AS INTEGER, j AS INTEGER, k AS INTEGER, q AS INTEGER
DIM a(42),b$<7)
b$(0}="понедельник": b$(1)="вторник ": b$(2)="среда
b$(3)="четверг ": b$(4)="пятница ": b$(5)="суббота
b$(6)="воскресенье"
CLS
PRINT "Календарь на ";М%;" месяц ";Y%;" года"
i=WeekDay(Y%,M%,l)
IFi=0 THEN i=7
q-MaxDay(Y%,M%)
FOR j=0 TO 41: a(j)=0: NEXT j
k=l
FOR j=i-l TO q+i-2: a(j)=k: k=k+l: NEXT j
FOR j=0 TO 6
LOCATE j+3,10: PRINT b$(j);
k=0
WHILE k<=35
IF a(k+j)<>0 THEN
PRINT USING "####";a(k+j); ELSE PRINT " ";
END IF k=k+7
WEND NEXT j END SUB
FUNCTION JD(Y%,M%,DT)
DIM a AS INTEGER, b AS INTEGER, mm AS INTEGER, yy AS INTEGER
DIM с AS LONG
b=0
yy=Y%
mm=M%
IF M%<3 THEN yy=yy-l: mm=mm+12
a=yy\100
IF Y%+M%/100!+DT/10000>1582.1015# THEN b=b+2-a+a\4
END IF
c=INT(365.25*yy) IF yy<0 THEN c=INT(365.25*yy-.75)
JD=c+INT(30.6001*(mm+1))+DT+1720994.5#+b END FUNCTION
FUNCTION MaxDay(Y%,M%)
MaxDay=DAYS(M%)
IF M%<>2 THEN EXIT FUNCTION
IF (Y% MOD 400=0)OR((Y% MOD 4=0)AND(Y% MOD l00<>0) ) THEN MaxDay=29
END IF END FUNCTION
FUNCTION WeekDay(Y%,M%,D%) dl!=D%+1.5
WeekDay=INT(JD(Y%,M%,dl!)) MOD 7 END FUNCTION
Программа 9_08.с
#include <stdio.h>
#include <conio.h>
void calendar(int Y,int M);
int week_day(int Y,int M,int D) ;
double JD(int Y,int M,double DT);
int max_day(int Y,int M);
main() {
int Y,M;
clrscr();
printf("Задайте год : ");
scanf("%d",&Y);
printf("Задайте месяц : ");
scanf("%d",&M);
calendar(Y,M);
getch(};
}
/*-------------------------------------------*/
void calendar'(int Y, int M) {
int a[42],i, j,k,q;
char *b[7]={"понедельник",
"вторник ",
"среда ",
"четверг ",
"пятница ",
"суббота ",
"воскресенье"}; clrscr();
printf("\ t Календарь на Id месяц %d года",М,У);
i=week_day(Y,M,1); /* определение дня недели для 1.M.Y */
if(i==0)i=7;
q=max day(Y,M); /* определение количества дней в месяце */
for(j=0; j<42; j++) a[j]=0;
for(j=i-l,k=l;
j<q+i-l; j++,k++) a[j]=k;
for(j=0; j<7; j++) {
gotoxy{10,j+3);
printf("%s",b[j]);
for(k=0; k<=35; k+=7)
if(a[k+j] != 0) printf("%4d",a[k+j]);
else printf("%4c",' '); }
return;
}
/*----------------------------------------*/
double JD(int Y,int M,double DT)
int a,b=0,m,y;
long c;
y=Y;
m=M;
if (M<3) { y--; m += 12; }
a = y/100;
if(Y+M/100.+DT/10000 > 1582.1015} b += 2-a+(int)(a/4.);
c=365.25*y; if(y<0)c=365.25*y-0.75;
return c+(long)(30.6001*(m+1))+DT+1720994.5+b;
}
/*---------------------------------*/
int week_day(int Y,int M,int D)
{
int q,m;
q = M+10;
m = (M-14)/12 + Y;
return
((13*(q-(q/13)*12)-1)/5+D+77+5*
(m%100)/4+m/400-(m/100)*2)%7;
}
/*-----------------------------------*/
int max_day(int Y,int M)
{ int days[]={31,28,31,30,31,31,30,31,30,31,30,31};
if(M != 2) return days[M-l];
begin
max_day:=days[M];
if (M=2)and((Y mod 400=0) or ( (Y mod 4=0) and (Y mod 100<>0) ) ) then
max_day:=2 9; end;
procedure calendar(Y,M:integer);
var
i,j,k,q:integer; a:array [0..41] of byte;
const
b:array [0..6] of string=('понедельник',
'вторник ', 'среда ',
'четверг ',
'пятница ',
'суббота ', 'воскресенье '};
begin clrscr;
write(' Календарь на ',М, ' месяц ',Y, ' года');
i:=week_day(Y,M,1);
if 1=0 then i:=7;
q:=max_day(Y,M);
for j:=0 to 41 do
a[j]:=0; k:=l;
for j:=i-l to q+i-2 do begin
a[j]:=k;
inc(k);
end;
for j:=0 to 6 do begin
gotoxy(10, j+3) ;
write(b[j]); k:=0;
while k<= 35 do begin;
if a[k+j] о 0 then
write(a[k+j]:4)
else write(' ':4); k:=k+7;
end;
end;
end;
begin {main}
clrscr;
write('Задайте год : ');
readln(Y);
write('Задайте месяц : ');
readln(M);
calendar(Y,M);
readln; end.
Задание 9.09. Преобразования времени суток
Составить процедуры упаковки и распаковки времени суток. Исходными данными для их работы должны быть либо показания часов (H — часы, M -минуты, S — секунды), либо часть суток, представленная вещественным числом t (0<= t <= 1).
Программа 9_09.bas
DECLARE SUB UnpackTime(T!,H%,M%,S%)
DECLARE FUNCTION PackTime!(H%,M%,S%)
КЕМ Упаковка и распаковка показаний часов
CLS
Н%=18: М%=0: S%=0
T=PackTime(H%,М%,S%)
PRINT USING "##:##:## = ###.##";H%;M%;S%;T
T= 5
UnpackTime T,H%,M%,S%
PRINT USING "##:##:## = ###.##";H%;M%;S%;T
END
FUNCTION PackTime(H%,M%,S%)
' Упаковка времени - перевод часов (Н%)
' минут (М%) и секунд (S%) в часть суток
PackTime = (Н% * 3600! + м% * 60 + S%) / 86400!
END FUNCTION
SUB UnpackTime(Т,H%,M%,S%)
' Распаковка времени - перевод части суток
' в часы (Н%), минуты (М%) и секунды (S%)
t1!=T*86400 H%=INT(tl1/3600! )
t1!=t1!-3600!*H% M%=INT(t1!/60!)
S%=INT(t1!-60!*M%)
END SOB
Программа 9_09.c
#include <stdio.h>
#include <conio.h>
double pack_time(int H, int M,int S) ;
void unpack_time(double t,int *H,int *M,int *S);
main() {
int H=18,M=0,S=0;
double T;
clrscr();
T=pack_time(H,M,S);
printf("\n%2d:%2d:%2d=%f",H,M,S,T);
T=0.75;
unpack_time(T,&H, &M,&S);
printf("\n%2d:%2d:%2d=%f",H,M,S,T);
getch();
}
/*----------------------------------------*/
double pack_time(int H,int M,int S)
/****************************************/
/* Упаковка времени - перевод часов (Н) .*/
/* минут (М) и секунд (S) в часть суток */
/****************************************/
{
return (H*3600.0+M*60+S)/86400.0; }
/*--------------------------------------*/
void unpack_time(double t,int *H,int *M,int *S)
/* Распаковка времени - перевод части суток */
/* в часы (Н), минуты (М) и секунды (S) */
{
double tl;
t1=t*86400;
*H=t1/3600.0;
t1=t1-3600.0*(*H);
*M=t1/60.0;
*S=t1-60.0*(*M);
}
Программа 9_09.pas
program pack_unpack;
uses Crt;
var
H,M,S:integer;
Т:double;
function pack_time(H,M,S:integer):double;
{ Упаковка времени - перевод часов (Н)минут (М) и секунд (S) в часть суток } begin
pack_time:=(H*3600.0+M*60+S)/86400.0;
end;
procedure unpack_time(t:double;var H,M,S:integer);
{ Распаковка времени - перевод части суток
в часы (Н), минуты (М) и секунды (S) }
var
t1:double; begin
t1:=t*86400;
H:=trunc(t1/3600.0) ;
t1:=t1-3600.0*H;
M:=trunc(t1/60.0);
S:=trunc(t1-60.0*M);
end;
begin {main}
clrscr;
H:=18; M:=0; S:=0;
T:=pack_tiine(H,M,S) ;
writeln(H:2,': ',M:2, ': ',S:2, ' =',T:6:2);
T:=0.5;
unpack_time(T,H,M,S);
writeln(H:2, ': ',M:2, ': ',S:2, ' =',T:6:2);
readln;
end.