Работа С Календарём

В настоящей статье приводится программа на языке С (компилятор Borland C++ ver. 3.1) для работы с календарем. Программа имеет три режима работы. Получения наименования дня для указанной даты, вывод календаря на указанный год и вычисления промежутка в днях для двух указанных дат.
Если Вы хотите научиться программировать на языках C, C++, C#, PASCAL, DELPHI, BASIC, PYTHON, FORTRAN или ASSEMBLER, то можете позвонить мне по тел. 8-916-579-85-49 или написать на почту michail123@bk.ru. Михаил Львович. Кроме того, я обучаю математике, физике и информатике.

Show »


// *****************************************************************
// Программа работы с календарём.
// Имеет три режима работы:
// 0 - при задании ГОД МЕСЯЦ ДАТА получаем ДЕНЬ_НЕДЕЛИ. REG=0.
// 1 - при задании ГОД выдает на экран/в файл календарь 
// на указанный год. REG=1. Файл при этом имеет имя ГОД.TXT.
// 2 - количество дней, прошедших между двумя введенными датами
// в формате ГОД МЕСЯЦ ДАТА. REG=2.
// Календарь Григорианский. Допустим год, начиная с 1582.
// *****************************************************************
#include <stdio.h>
#include <conio.h>
#include <stdlib.h>
#include <math.h>
// Прототипы используемых функций
int pgw(int );
void fwp(int );
void fwim(int );
long fodn(int , int , int );
 FILE *in; // текстовый файл
 int mdg[6*7*12]; // массив дней года
 char dn[]={"ПОНЕДЕЛЬНИК ВТОРНИК СРЕДА ЧЕТВЕРГ ПЯТНИЦА СУББОТА
 ВОСКРЕСЕНЬЕ"};
 char mnm[]={" ЯНВАРЬ ФЕВРАЛЬ МАРТ АПРЕЛЬ МАЙ ИЮНЬ ИЮЛЬ АВГУСТ
 СЕНТЯБРЬ ОКТЯБРЬ НОЯБРЬ ДЕКАБРЬ"};
 char mndn[]={"ПНВТСРЧТПТСБВС"};
 int pw;
 int md[12]={31,28,31,30,31,30,31,31,30,31,30,31};

int main(void)
{
 int d,m,g,i,j,k,kd,id,jmn;
 int dn1,mn1,gn1,dk1,mk1,gk1;
 int ms,nm,jm,reg;
 clrscr();
 kd=0;
 puts("Определить день года (0), календарь на год (1) или кол-во дней между датами (2)");
 scanf("%d",&reg);
 if (reg==1)
 {
 puts("nВведите ГОД и устр-во вывода 1/0 экран/файл ");
 scanf("%d%d",&g,&pw);
 if(!pw)
 {
 char fname [9]={" .txt"}; // имя файла
 itoa(g,fname,10);
 fname[4]='.';
 fname[8]=0;
 // Открыть файл в режиме записи (w) текста (t)
 if (!(in=fopen(fname,"wt")))
 {
 printf("Ошибка при обращении к файлу %sn", fname);
 getch();
 return 0;
 }
 }
 fprintf(in,"КАЛЕНДАРЬ НА %d ГОД",g);
 }
 else
 {
 if (reg==0)
 {
 puts("nВведите nГОД МЕСЯЦ ДАТУ");
 scanf("%d%d%d",&g,&m,&d);
 } 
 else
 {
 if (reg==2)
 {
 // Введение анализируемых дат.
 puts("Введите анализируемые даты в формате ГОД МЕСЯЦ ДАТУn");
 scanf("%d%d%d%d%d%d",&gn1,&mn1,&dn1,&gk1,&mk1,&dk1);
 printf("nМежду указанными датами прошло %ld дней ",
 labs(fodn(dn1,mn1,gn1)-fodn(dk1,mk1,gk1)));
 getch();
 return 1;
 }
 }
 }
 // если текущий год високосный, то корректирую число дней в ФЕВРАЛЕ
 md[1]+=pgw(g);
 // За ОСНОВУ беру 1 января 1582 года - вторник (=2) = 01 01 1582 2.
 // подсчет кол-ва дней от ОСНОВЫ до требуемой.
 // В обычном годе 365=52*7+1 дней, т.е. каждый обычный год дает сдвиг 
 // на один день вперед. Т.е. от ОСНОВЫ сдвиг вперед по обычным годам
 // в днях = ГОД-1582. Каждый високосный год дает ещё +1 день.
 // Таким образом общий сдвиг от ОСНОВЫ к первому дню нужного года=
 for(i=1582,kd=g-i; i<g; kd+=pgw(i++));
 if(!reg)
 {
 // подсчет дополнительных дней, прошедших от начала нужного года
 // до первого дня нужного месяца
 for (i=0;i<m-1;i++) kd+=md[i];
 // до требуемого дня нужного месяца
 kd+=d;
 }
 // пересчитываю все эти сдвиги в номер текущего дня.
 // В зависимости от режима REG 0/1 +01. 
 id=((kd+4+reg)%7);
 if (!id) id=7;
 if (!reg)
 {
 printf("Днем недели для даты %d %d %d является ",d,m,g);
 for(i=(id-1)*11,j=1;j<=11;i++,j++) printf("%c",dn[i]);
 getch();
 return 1;
 }
 // Заполнение всего массива ДАТ.
 // На каждый месяц отвожу 42 позиций, внутри которых свободно
 // (с учетом первого дня месяца) подряд располагаются дни месяца.
 // Цикл по месяцам ГОДА.
 // Первый день очередного месяца выпадает на день номер k внутри
 // 42-х дней, отведенных месяцу.
 for(i=0,id--;i<12;i++)
 {
 // цикл по дням очередного месяца. Заполняю его массив
 // подряд днями.
 for(j=1,k=i*42+id;j<=md[i];)
 {
 // отслеживаю текущий день недели
 id++;
 id=((id<=7)?(id):(id-7));
 mdg[k++]=j++;
 // после заполнения массива надо подготовиться к следующему месяцу.
 // Его (следующего месяца) первый день будет отстоять от его начала
 // так, чтобы он был следующим днем недели по отношению к последнему
 // дню предыдущего месяца.
 }
 }
 // Вывод полученного календаря 
 do
 {
 puts("Укажите формат вывода - 2/3/4/6 месяцев в строку ");
 scanf("%d",&ms);
 } while(!((ms==2) || (ms==3) || (ms==4) || (ms==6)));
 int npmg=-ms; // номер первого месяца группы
 // Цикл по выводимым горизонтально группам месяцов
 nm=1;
 for(i=1;i<=12/ms;i++)
 {
 npmg+=ms;
 // вывод в верхней строке названий месяцев
 fwp(6); // вызов функции вывода пробелов
 (pw)?(printf("n")):(fprintf(in,"n"));
 for(j=1;j<=ms;j++)
 {
 // вывод пробелов ПЕРЕД именем массива
 fwp(5);
 // вывод самого имени массив
 fwim(nm++);
 // вывод пробелов ПОСЛЕ имени массива
 fwp(5);
 }
 int jmn1=npmg*42-1;
 // Вывожу сами строки дат месяцев. Цикл по дням недели.
 for(k=0;k<7;k++)
 {
 jmn1++;
 (pw)?(printf("n%c%c",mndn[k*2],mndn[k*2+1])):
 (fprintf(in,"n%c%c",mndn[k*2],mndn[k*2+1]));
 // цикл по дням месяцев, выводимым в строку

 for(jm=1,jmn=jmn1;jm<=6*ms;jm++)
 {
 (!mdg[jmn])?
 ((pw)?(printf(" ")):(fprintf(in," "))):
 ((pw)?(printf("%3d",mdg[jmn])): (fprintf(in,"%3d",mdg[jmn])));
 jmn+=7;
 }
 }
 }
 if(!pw) 
 {
 fclose(in);
 puts("Календарь выведен в файл");
 }
 getch();
 return 1;
}

// Функция проверки года на високосность ДА/НЕТ 1/0.
// Високосный год тот, номер готорого нацело делится на 4,
// кроме тех, номер которых кончается на 00 и не делится
// нацело на 400 (например 1800).
int pgw(int g)
{
 return ((g%4==0)&&(!((g%400!=0)&&(g%100)==0)));
}

// функция вывода пробелов на экран или в файл
void fwp(int n)
{
 for(int i=1;i<=n;((pw)?(printf(" ")):(fprintf(in," "))),i++);
// 1 02 2 3 4 43 5 6 650 1
}

// функция вывода имени массива
void fwim(int n)
{
 for(int i=1;i<=8;(pw)?(printf("%c",mnm[(n-1)*8+i++])):
 (fprintf(in,"%c",mnm[(n-1)*8+i++])));
}

// Функция определения числа дней, прошедших от введения
// Григорианского календаря до указанной даты.
long fodn(int d, int m, int g)
{
 int i;
 // подсчет общего кол-ва дней, прошедших от ОСНОВЫ до первого
 // января искомого года.
 long kd=(g-1582)*365;
 // За ОСНОВУ беру 1 января 1582 года - пятница (=5) = 01 01 1582 5.
 // подсчет кол-ва дней от ОСНОВЫ до требуемой.
 // Вначале считаю сколько високосных годов будет от ОСНОВЫ
 // до года непосредственно предшествующего нужному
 for(i=1582; i<g; kd+=pgw(i++));
 // подсчет дополнительных дней, прошедших от начала нужного года
 // до первого дня нужного месяца
 for (i=0;i<m-1;kd+=md[i++]);
 // до требуемого дня нужного месяца
 kd+=d;
 // если текущий год високосный и месяц позже февраля, то +1
 if (m>1) kd+=pgw(g);
 return kd;
}