1 Strukture i funkcije za očitavanje vremena
U datoteci <time.h> definisano je nekoliko funkcija i struktura imena tm, za očitavanje i manipulisanje vremena i datuma.
Za očitavanje vremena u ovom zaglavlju je deklarisana funkcija
time_t time(time_t *tp);
koja vraća vrednost time_t tipa, tj. kardinalni broj koji predstavlja trenutno vreme (obično je to broj sekundi od 1.1.1970.).
Parametar tp, ako nije NULL, takođe prihvata trenutno vreme u *tp.
Tip time_t je typedef za celobrojnu vrednost . U većini implementacija funkcija time()
vraća vrednost koja je jednaka vremenu u sekundama koje je proteklo od 01.1.1970. godine.
Ista se vrednost postavlja i u dereferencirani pokazivač tp, ukoliko on nije NULL.
DA LI ZNATE ZA PROBLEM 2038? (tj. problem petak 13: Tue Jan 19 03:14:07 2038 - > Fri Dec 13 20:45:52 1901)
Da bi se olakšala konverzija ovog vremena u stvarno vreme i datum, definisana je struktura tm sa sledećim članovima:
struct tm /* opisuje vreme i datum */
{
int tm_sec; /* sekunde 0..61 po knjizi Kernighan & Ritchie, vidi dole*/
int tm_min; /* minute 0..59 */
int tm_hour; /* sat 0..23 */
int tm_mday; /* dan 1..31 */
int tm_mon; /* mesec 0..11 */
int tm_year; /* broj godina nakon 1900 */
int tm_wday; /* dan u sedmici 0..6 */
int tm_yday; /* dan u godini 0..365 */
int tm_isdst; /* da li je dan promene sata 0..1 */
};
Napomena: ako dan promene sata nije implementiran tada tm_isdst ima negativnu vrednost.
Broj sekundi može biti veći od 59 u slučaju prestupnog vremena (po knjizi K&R). Meseci su kodirani tako da 0 označava januar, 1 februar itd. Dani u sedmici su kodirani tako da 0 označava nedelju, 1 ponedeljak itd.
Stvarna godina se dobije tako da se članu tm_year doda vrednost 1900
(npr. u godini 2007. godini član tm_year sadrži vrednost 107).
localtime, gmtime
Konverzija vremena iz formata time_t u struct tm vrši se funkcijom localtime(), kada se želi dobiti lokalno vreme,
ili funkcijom gmtime() za dobijanje univerzalnog vremena u nultom meridijanu.
struct tm *localtime(const time_t *t);
struct tm *gmtime(const time_t *t);
Obe funkcije primaju adresu promenljive koja sadrži vreme u formatu time_t, a vraćaju
pokazivač na statičku strukturu tipa tm (sadržaj se obnavlja pri svakom pozivu ovih funkcija) .
ctime, asctime
Ako se želi dobiti zapis vremena u obliku stringa, mogu se koristiti funkcije
char *ctime(const time_t *t);
char *asctime(const struct tm *tp);
Funkcija ctime() za argument koristi adresu promenljive koja sadrži vreme u formatu time_t,
a funkcija asctime() za argument koristi pokazivač na strukturu tm.
Obe funkcije vraćaju pokazivač statičkog stringa koji sadrži zapis vremena u standardnom formatu.
Na primer, sekvenca naredbi
time_t t = time(NULL);
char *s = ctime(&t);
puts(s);
generise ispis:
Thu Jan 25 14:21:20 2007
Uočite da je rezultat poziva ctime(&t) ekvivalentan pozivu asctime(localtime(&t)) .
Standardna verzija je prilagođena američkim standardima. Ako se želi napisati vreme u
formatu 25.01.2007 14:21
tada se može koristiti sledeće iskaz:
/* ispisuje datum i vreme u formatu 25.01.2007 14:21 */
time_t t = time(NULL);
struct tm *p = localtime(&t);
printf("%.2d.%.2d.%.2d %2d:%.2d\n",
p->tm_mday, p->tm_mon + 1,
p->tm_year +1900,
p->tm_hour, p->tm_min);
#include <time.h> #include <stdio.h> struct tm *newtime; time_t aclock; void main( void ) { time( &aclock ); /* dobijanje tekuceg vremena u sekunda */ newtime = localtime( &aclock ); /* Konverzija vremena u struct tm oblik */ /* Stampa vremena kao stringa */ printf( "Tekuci dan i vreme su: %s", asctime( newtime ) ); }
Tekuci dan i vreme su: Sun Jan 21 20:27:01 2007
strftime
Funkcija strftime() se koristi za formatirani ispis vremena. Format se zadaje kao kod printf() funkcije.
Prototip funkcije strftime()glasi:
size_t strftime(char *buf, size_t bufsize, const char *fmt, const struct tm *tp);
Prvi argument je string str u koji se vrši formatirani zapis.
Drugi argument (bufsize) ograničava broj znakova stringa.
Treći parametar je string u kojem se zapisuje format ispisa nizom specifikatora oblika %x (kao kod printf() funkcije).
Poslednji argument je pokazivač strukture tm.
Funkcija vraća broj znakova u stringu ili 0 ako nije moguće generisati formatirani string.
Specifikatori formata su
%a skracenica od tri slova za ime dana u sedmici (eng. Sun, Mon, Tue,..)
%A puno ime dana u sedmici (eng...)
%b skracenica od tri slova za ime meseca (eng. Jan, Feb, Mar,...)
%B puno ime meseca (eng....)
%c kompletni zapis vremena i datuma
%d dan u mesecu (1..31)
%H sat u formatu (1..24)
%I sat u formatu (1..12)
%j dan u godini (1..366)
%m mesec u godini (1..12)
%M minut
%p AM/PM (eng.) string koji označava jutro ili popodne
%S sekunde
%U broj za sedmicu u godini (1..52) - 1 određen prvom nedeljom
%w broj za dan u sedmici (0-nedelja)
%W broj za sedmicu u godini (1..52) - 1 određen prvim ponedeljkom
%x kompletni zapis datuma
%X kompletni zapis vremena
%y zadnje dve cifre godine
%Y godina u formatu s 4 cifre
%Z ime vremenske zone (ako postoji )
%% znak %
Zadatak 2: NCP koji demonstrira korištenje funkcija za datum i vreme tako sto ih ispisuje u:
standardnom formatu (dan mesec redni_broj_dana vreme godina),
u formatiranom zapisu oblika Dan Mesec Godina Cas Minut ,
lokalno vreme.
/* Prikazuje datum i vreme u tri formata*/
#include <stdio.h>
#include <time.h>
int main()
{
time_t vreme = time(NULL); /* tekuce vreme u sekundama*/
struct tm *ptr; /* struktura za laksu konverziju tekuceg vremena u datum i vreme */
char datum_str[20]; /* string datum i vreme */
/* ispisuje datum i vreme u standardnom formatu */
puts(ctime(&vreme));
/* ispisuje datum i vreme u obliku D M G Cas Minut pomoću strftime funkcije */
strftime(datum_str, sizeof(datum_str),"%d.%m.%y %H:%M\n", localtime(&vreme));
puts(datum_str);
/* ispisuje datum i vreme u proizvoljnom formatu */
ptr = localtime(&vreme);
printf("%.2d.%.2d.%.2d %2d:%.2d\n",
ptr->tm_mday, ptr->tm_mon+1, ptr->tm_year +1900,
ptr->tm_hour, ptr->tm_min);
return 0;
}
Dobije se ispis:
Mon Jan 22 20:13:06 2007
22.01.07 20:13
22.01.2007 20:13
Za obradu vremena se koriste i sledeće funkcije:
mktime
time_t mktime(struct tm *tp)
Funkcija mktime() pretvara zapisa iz strukture tm u time_t format. Korisna je u tzv.
kalendarskim proračunima. Kada je potrebno dodati nekom datumu n dana, tada se može upisati
datum u tm strukturu, povećati član tm_mday za n, zatim pozivom mktime() se dobije
time_t vrednost koja odgovara novom datumu.
Zadatak 3: NCP koji na standardni izlaz ispisuje tekuce vreme u formatu datum i vreme, a potom ucitava od korisnika ceo broj dana i ispisuje datum i vreme nakon unetog broja dana.
#include <time.h> #include <stdio.h> void main( void ) { struct tm kada; /* struktura za konverziju sekundi u datum i vreme */ __time64_t sada, rezultat; /* tekuce, buduce vreme */ int dani; /* broj dana sa stdin */ _time64( &sada ); kada = *_localtime64( &sada ); printf( "Tekuce vreme je %s\n", asctime( &kada ) ); printf( "Unesite broj buducih dana: " ); scanf( "%d", &dani ); kada.tm_mday = kada.tm_mday + dani; if( (rezultat = _mktime64( &kada )) != (time_t)-1 ) printf( "Za %d dana vreme ce biti %s\n", dani, asctime( &kada ) ); else perror( "_mktime64 greska" ); }
Tekuce vreme je Fri Jan 19 10:04:20 2007 Unesite broj buducih dana: Za 20 dana vreme ce biti Thu Feb 8 10:04:20 2007
32-bitna verzija istog programa (zbog starijih gcc kompajlera)
difftime
double difftime(time_t t1, time_t t2)
Funkcija difftime() vraća realnu vrednost koja je jednaka razlici vremena t1 i t2 u sekundama.
#include <stdio.h> #include <stdlib.h> #include <time.h> void main( void ) { time_t start, kraj; long i; /* brojac u ciklusu */ double rez, vreme; /* rezultat mnozenja, proteklo vreme */ printf( "Trazeno mnozenje traje...\n" ); time( &start ); /* POCETAK MERENJA */ for( i = 0; i < 10000000; i++ ) rez = 3.63 * 5.27; time( &kraj ); /* KRAJ MERENJA */ vreme = difftime( kraj, start ); printf( "\n %6.0f sekundi.\n", vreme ); }
Trazeno mnozenje traje... 2 sekunde.
clock
clock_t clock(void);
Funkcija clock() služi za preciznije merenje vremena nego sto je to moguće sa prethodnim
funkcijama. Ona vraća vrednost procesorskog merača vremena, koji startuje na početku
programa, u jedinicama koje su znatno manje od sekunde (nekoliko milisekundi). Koliko je tih
jedinica u jednoj sekundi određeno je konstantom CLOCKS_PER_SEC.
To znači da izraz: (double)clock()/CLOCKS_PER_SEC
daje vrednost koja je jednaka vremenu (u sekundama) od startovanja programa.
Zadatak 6: NCP koji ispituje vremensku rezolucija funkcije clock(), tj. minimalno vreme koje se njome može meriti,
a potom pomoću funkcije clock() izmeriti potrebno vreme za izvršenje sinusne funkcije.
#include <stdio.h>
#include <math.h>
#include <time.h>
int main()
{
double start, stop;
double n ; /* argument funkcije sinus, neinicijalizovan */
double rezolucija;
start =(double)clock()/CLOCKS_PER_SEC;
/* MERENJE REZOLUCIJE, tj. minimalnog vremena za merenje funkcijom clock */
do {
stop=(double)clock()/CLOCKS_PER_SEC;
}
while (stop == start);
rezolucija = stop-start;
printf("Rezolucija CLOCK-a je %g sekundi\n" , rezolucija);
start =(double)clock()/CLOCKS_PER_SEC;
stop = start + 10*rezolucija;
do {
n += 1.0;
sin(n);
}
while (stop > (double)clock()/CLOCKS_PER_SEC);
printf("Funkcija sin se izvršava %g sekundi\n" , 10*rezolucija/n);
return 0;
}
Izlaz:
Rezolucija CLOCK-a je 0.015 sekundi
Funkcija sin se izvrsava u 2.3543e-007 sekundi
Rezolucija funkcije clock() je 15 ms. U drugoj petlji, u kojoj se računa funkcija sin(),
odabrano je da se ona ponavlja za vreme koje je 10 puta veće od rezolucije clock()-a. Na taj
način merenje vremena izvršenja sinus funkcije vrši se s greškom koja je manja ili jednaka 10%.
Zadatak 7. NCP koji uspavljuje aktivnosti programa za 3 sekunde, a potom za dati broj ponavljanja izvrsava prazan ciklus
i meri proteklo vreme.
#include <stdio.h> #include <stdlib.h> #include <time.h> void sleep( clock_t cekanje ); void main( void ) { long i = 600000L; /* broj ponavljanja praznog ciklusa, tj. ciklusa bez tela */ clock_t start, stop; double vreme; /* proteklo vreme rada */ /* Uspavljivanje za 3 sekunde. */ printf( "Spavam 3 sekunde\n" ); sleep( (clock_t)3 * CLOCKS_PER_SEC ); printf( "Probudio sam se!\n" ); /* Merenje proteklog vremena rada ciklusa. */ printf( "Da bi se izbrsilo %ld praznih iteracija potrebno je ", i ); start = clock(); while( i-- ) ; stop = clock(); vreme = (double)(stop - start) / CLOCKS_PER_SEC; printf( "%2.1f sekundi\n", vreme ); } /* Pauza za dati broj sekundi. */ void sleep( clock_t cekaj ) { clock_t rez; rez = cekaj + clock(); while( rez > clock() ) ; }
Spavam 3 sekunde Probudio sam se! Da bi se izbrsilo 600000 praznih iteracija potrebno je 0.1 sekundi
Zadatak 8. NCP koji ucitava dimenziju niza realnih brojeva, unosi niz brojeva ili u slucaju dimenzije vece od 20 generise niz slucajnih brojeva date dimenzije, a potom ih sortira metodama bubble sort i metodom quick sort. Izmeriti vreme trajanja sortiranja. Eksperimentisite sa razlicitim dimenzijama niza ( manje od 1000, vise od 1000).
#include <stdlib.h>
#include <stdio.h>
#include <time.h>
#include <string.h>
void bubble(int a[], int n);
void quick(int a[], int n);
main()
{
int *niz, *nizkopija;
clock_t s1,s2,f1,f2;
double v1,v2;
int i,n;
printf("\nUnesite dimenziju niza: \n");
scanf("%d",&n);
niz=(int *)malloc(n*sizeof(int));
nizkopija=(int *)malloc(n*sizeof(int));
for(i=0;i<n;i++) niz[i]=rand();
memcpy(nizkopija,niz,n*sizeof(int));
s1=clock();
bubble(niz,n);
f1=clock();
s2=clock();
quick(nizkopija,n);
f2=clock();
v1=(double)(f1-s1)/CLOCKS_PER_SEC; /* v1=f1-s1 */
v2=(double)(f2-s2)/CLOCKS_PER_SEC; /* v2=f2-s2 */
free(niz);
free(nizkopija);
printf("\n Bubble: %g Quick: %g\n", v1,v2);
}
void bubble( int a[], int n)
{ int i, j, b, dalje;
for(dalje=1, i=0; i< n-1 && dalje; i++)
for(dalje=0, j=n-2; j>=i;j--)
if( a[i]>a[j])
{
b=a[j]; a[j]=a[j+1]; a[j+1]=b;
dalje=1;
}
}
void quick (int a[], int n) {
int i,j,b;
if (n>1)
{
i=-1; j=n-1;
while(1)
{
do i++; while (a[i] < a[n-1]);
do j--; while (j>=0 && a[j]>a[n-1]);
if(i >= j) break;
b=a[i]; a[i] = a[j]; a[j] = b;
}
b = a[i]; a[i] = a[n-1]; a[n-1] = b;
quick (a, i); quick (a+i+1, n-i-1);
}
}