C-keele ajafunktsioonid: täielik juhend koos näidetega

目次

1. Sissejuhatus

C-keel on programmeerimiskeel, mida kasutatakse laialdaselt süsteemiprogrammeerimises ja manussüsteemides. Nende seas on “aja käsitlemine” paljudes programmides oluline element. Näiteks logisüsteem, mis kuvab praeguse aja, või taimeri funktsioon, mis käivitab määratud ajal kindla protsessi – mõlemad vajavad ajaga töötamist.

Selles artiklis selgitame peamiselt standardteeki time.h, mida kasutatakse aja töötlemiseks C-keeles. Selle teegi abil saab hankida süsteemi praeguse aja, vormindada ja kuvada kellaaega. Lisaks käsitleme ka tuntud tulevast probleemi, mida nimetatakse „2038. aasta probleemiks“, et anda põhiteadmisi aja korrektsest käsitlemisest.

Artikkel on kirjutatud nii, et ka algajad mõistaksid seda, liikudes samm-sammult läbi põhimõistete ja praktiliste näidete. Lugedes õpid järgmisi teemasid:

  • Põhiteadmised aja töötlemisest C-keeles
  • Praeguse aja hankimine ja kuvamine
  • Kellaaja vormindamine ja manipuleerimine
  • Levinud probleemid ajaga töötamisel ja nende lahendused

Nende teadmiste abil saad rakendada aja töötlemist logimise, ajastamise ja taimerite juures. Järgmises jaotises vaatleme üksikasjalikult põhilisi andmetüüpe ja funktsioone, mida kasutatakse aja käsitlemisel C-keeles.

2. Põhiteadmised aja käsitlemiseks C-keeles

Aja töötlemiseks C-keeles kasutatakse standardteeki time.h. See päisefail pakub andmetüüpe ja funktsioone süsteemiaja hankimiseks ja töötlemiseks. Siin selgitame üksikasjalikult vajalikke põhimõisteid aja käsitlemisel.

Mis on time.h?

time.h on C-keele standardteek, mis toetab aja töötlemist. Selle abil saab hõlpsasti hankida süsteemi praeguse aja, vormindada ajandmeid ning teha liitmis- ja lahutustehted.

Peamised andmetüübid ja funktsioonid, mida kasutatakse:

  • Andmetüübid: time_t, struct tm
  • Funktsioonid: time(), localtime(), strftime() jne

Põhilised andmetüübid, mida kasutatakse aja töötlemisel

C-keeles aja käsitlemiseks on vaja mõista järgmisi andmetüüpe.

1. time_t

time_t on andmetüüp süsteemiaja esitamiseks. See salvestab sekundite arvu, mis on möödunud alates 1. jaanuarist 1970 kell 00:00:00 (Unix epoch). See on kõige põhilisem tüüp, mida kasutatakse praeguse aja hankimisel programmis.

Näide kasutusest
#include <stdio.h>
#include <time.h>

int main() {
    time_t now = time(NULL); // Hangi praegune aeg
    printf("Praegune aeg sekundites: %ld\n", now);
    return 0;
}

See kood kuvab süsteemi praeguse aja sekundites.

2. struct tm

struct tm on struktuur, mida kasutatakse aja detailsemaks esitamiseks. See salvestab andmed nagu aasta, kuu, päev, tund, minut ja sekund.

Struktuuri liikmed

struct tm sisaldab järgmisi liikmeid:

  • tm_sec: sekundid (0–60)
  • tm_min: minutid (0–59)
  • tm_hour: tunnid (0–23)
  • tm_mday: kuupäev (1–31)
  • tm_mon: kuu (0–11, kus 0 = jaanuar)
  • tm_year: aastad alates 1900. aastast
  • tm_wday: nädalapäev (0–6, kus 0 = pühapäev)
  • tm_yday: aasta päev (0–365)
  • tm_isdst: suveaeg (1 = kehtib, 0 = ei kehti, -1 = teadmata)
Näide kasutusest
#include <stdio.h>
#include <time.h>

int main() {
    time_t now = time(NULL);
    struct tm *local = localtime(&now); // Konverteeri lokaalaega

    printf("Praegune kuupäev ja kellaaeg: %d-%02d-%02d %02d:%02d:%02d\n",
           local->tm_year + 1900, // aasta aluseks on 1900
           local->tm_mon + 1,     // kuud algavad nullist
           local->tm_mday,
           local->tm_hour,
           local->tm_min,
           local->tm_sec);

    return 0;
}

See kood kuvab praeguse kuupäeva ja kellaaja formaadis „AAAA-KK-PP TT:MM:SS“.

Muud andmetüübid aja mõõtmiseks

1. clock_t

clock_t on andmetüüp protsessi käivitamise aja mõõtmiseks. Koos funktsiooniga clock() saab mõõta koodi täitmise kestust.

Näide kasutusest
#include <stdio.h>
#include <time.h>

int main() {
    clock_t start, end;
    double cpu_time_used;

    start = clock();
    // Kood, mille täitmise aega mõõdetakse
    for (volatile long i = 0; i < 100000000; i++);
    end = clock();

    cpu_time_used = ((double)(end - start)) / CLOCKS_PER_SEC;
    printf("Täitmisaeg: %f sekundit\n", cpu_time_used);

    return 0;
}

See kood mõõdab määratud tsükli täitmiseks kuluvat aega.

Andmetüüpide kokkuvõte

Allpool on tabel peamistest andmetüüpidest, mida kasutatakse aja käsitlemisel.

AndmetüüpSelgitusPõhiline kasutus
time_tSüsteemiaja hoidmine (sekundites)Praeguse aja hankimine
struct tmDetailne aja info (aasta, kuu, päev, tund, minut, sekund)Aja vormindamine ja manipuleerimine
clock_tProtsessi täitmisaegTäitmise kestuse mõõtmine

3. Kuidas hankida praegune aeg

C-keeles saab praegust aega hankida time.h päisefaili kaudu pakutava funktsiooniga time(). Selles jaotises selgitame põhilist kasutust ning teisendamist lokaalseks ajaks või UTC-ajaks.

Praeguse aja hankimise põhitõed

Funktsioon time()

time() tagastab süsteemiaja väärtuse time_t tüübis. See funktsioon on väga lihtne: piisab NULL argumendist, et hankida praegune aeg.

Näide kasutusest
#include <stdio.h>
#include <time.h>

int main() {
    time_t now = time(NULL); // Hangi praegune aeg
    printf("Praegune aeg (sekundites): %ld\n", now);
    return 0;
}

Väljundi näide

Praegune aeg (sekundites): 1700000000

Aja teisendamine inimesele loetavasse vormi

Teisendamine lokaalseks ajaks: localtime()

Funktsioon localtime() teisendab time_t väärtuse lokaalse ajavööndi alusel struct tm struktuuriks.

Näide kasutusest
#include <stdio.h>
#include <time.h>

int main() {
    time_t now = time(NULL); // Hangi praegune aeg
    struct tm *local = localtime(&now); // Teisenda lokaalseks ajaks

    printf("Praegune kohalik aeg: %d-%02d-%02d %02d:%02d:%02d\n",
           local->tm_year + 1900, // aasta aluseks on 1900
           local->tm_mon + 1,     // kuud algavad nullist
           local->tm_mday,
           local->tm_hour,
           local->tm_min,
           local->tm_sec);

    return 0;
}

Väljundi näide

Praegune kohalik aeg: 2025-01-12 15:30:45

Teisendamine UTC-ajaks: gmtime()

Funktsioon gmtime() teisendab time_t väärtuse universaalseks ajaks (UTC) vastavalt struct tm struktuuri.

Näide kasutusest
#include <stdio.h>
#include <time.h>

int main() {
    time_t now = time(NULL); // Hangi praegune aeg
    struct tm *utc = gmtime(&now); // Teisenda UTC-ajaks

    printf("Praegune UTC aeg: %d-%02d-%02d %02d:%02d:%02d\n",
           utc->tm_year + 1900,
           utc->tm_mon + 1,
           utc->tm_mday,
           utc->tm_hour,
           utc->tm_min,
           utc->tm_sec);

    return 0;
}

Väljundi näide

Praegune UTC aeg: 2025-01-12 06:30:45

UTC ja kohaliku aja erinevus

  • UTC (Koordineeritud maailmaaeg)
    On maailma standardaeg, mille järgi määratakse kõik ajavööndid.
  • Kohalik aeg
    On süsteemi ajavööndi seadete järgi kohandatud aeg.

Näiteks Jaapani standardaeg (JST) on UTC+9 tundi. Seetõttu on localtime() ja gmtime() väljundite vahel 9-tunnine erinevus.

Praeguse aja kuvamine stringina

Funktsioon ctime()

ctime() on lihtne funktsioon, mis kuvab time_t väärtuse otse stringina.

Näide kasutusest
#include <stdio.h>
#include <time.h>

int main() {
    time_t now = time(NULL);
    printf("Praegune aeg: %s", ctime(&now)); // Kuva aeg stringina
    return 0;
}

Väljundi näide

Praegune aeg: Sat Jan 12 15:30:45 2025

Tähtis märkus

  • Väljund on alati inglise keeles.
  • Kui on vaja paindlikumat vormingut, kasuta funktsiooni strftime() (selgitatakse järgmises jaotises).

Kokkuvõte

  • Praeguse aja hankimiseks kasuta funktsiooni time().
  • Kohalik aeg teisendatakse funktsiooniga localtime(), UTC-aeg funktsiooniga gmtime().
  • Lihtsaks stringi kuvamiseks kasuta funktsiooni ctime().

4. Aja vormindamine: strftime() kasutamine

Kui soovid C-keeles kuupäeva ja kellaaja kuvada inimesele loetaval kujul, siis strftime() funktsioon võimaldab määrata paindlikud vormingud. Selle abil saab lisaks aastale, kuule, päevale, tunnile, minutile ja sekundile näidata ka näiteks nädalapäeva või aasta järjestikust päeva.

Selles jaotises tutvustame strftime() funktsiooni põhilist kasutust ja kasulikke näiteid.

Mis on strftime() funktsioon?

strftime() teisendab struct tm andmed stringiks vastavalt määratud vormingu spetsifikaatoritele.

Funktsiooni prototüüp

size_t strftime(char *s, size_t max, const char *format, const struct tm *tm);
  • s: puhver, kuhu salvestatakse vormindatud string.
  • max: puhvri maksimaalne suurus.
  • format: vormingu spetsifikaatorid.
  • tm: struct tm, mida vormindatakse.

Tagastusväärtus

Tagastab teisendatud stringi pikkuse baitides. Kui tekib viga, tagastatakse 0.

Põhiline kasutus

Allpool on näide, kuidas kuvada praegune aeg kujul „AAAA-KK-PP TT:MM:SS“.

Näide kasutusest

#include <stdio.h>
#include <time.h>

int main() {
    time_t now = time(NULL);            // Hangi praegune aeg
    struct tm *local = localtime(&now); // Teisenda lokaalseks ajaks

    char buffer[80];                    // Puhver vormindatud stringi jaoks
    strftime(buffer, sizeof(buffer), "%Y-%m-%d %H:%M:%S", local);

    printf("Vormindatud aeg: %s\n", buffer);
    return 0;
}

Väljundi näide

Vormindatud aeg: 2025-01-12 15:30:45

Levinud vormingu spetsifikaatorid

SpetsifikaatorSelgitusNäide väljundist
%YAasta (4 numbrit)2025
%mKuu (01–12)01
%dPäev (01–31)12
%HTund (00–23)15
%MMinutid (00–59)30
%SSekundid (00–60)45
%ANädalapäev (täisnimi, inglise keeles)Laupäev
%aNädalapäev (lühendatud, inglise keeles)Sat
%jAasta järjestikune päev (001–366)012
%pAM või PM (sõltub lokaalist)PM

Näide

  • Vorming: "%A, %d %B %Y"
  • Väljund: Laupäev, 12 Jaanuar 2025

Praktilised näited: kohandatud vormingud

1. Jaapani stiilis kuupäev

Jaapanis kasutatakse sageli vormi „AAAA年KK月PP日 TT時MM分SS秒“.

Näide kasutusest
#include <stdio.h>
#include <time.h>

int main() {
    time_t now = time(NULL);
    struct tm *local = localtime(&now);

    char buffer[80];
    strftime(buffer, sizeof(buffer), "%Y年%m月%d日 %H時%M分%S秒", local);

    printf("Praegune aeg: %s\n", buffer);
    return 0;
}

Väljundi näide

Praegune aeg: 2025年01月12日 15時30分45秒

2. Logifailide ajatempli loomine

Süsteemilogides kasutatakse sageli vormingut „AAAA-KK-PP_TT-MM-SS“.

Näide kasutusest
#include <stdio.h>
#include <time.h>

int main() {
    time_t now = time(NULL);
    struct tm *local = localtime(&now);

    char buffer[80];
    strftime(buffer, sizeof(buffer), "%Y-%m-%d_%H-%M-%S", local);

    printf("Logi ajatemper: %s\n", buffer);
    return 0;
}

Väljundi näide

Logi ajatemper: 2025-01-12_15-30-45

3. Vorming ingliskeelse nädalapäevaga

Genereerib näiteks kuju „Sat, 12 Jan 2025“.

Näide kasutusest
#include <stdio.h>
#include <time.h>

int main() {
    time_t now = time(NULL);
    struct tm *local = localtime(&now);

    char buffer[80];
    strftime(buffer, sizeof(buffer), "%a, %d %b %Y", local);

    printf("Inglise vorming: %s\n", buffer);
    return 0;
}

Väljundi näide

Inglise vorming: Sat, 12 Jan 2025

4. Vigade käsitlemine

Kui strftime() tagastab 0, võib põhjuseks olla liiga väike puhver või vale vorming. Kontrolli:

  • Kas puhvri suurus (sizeof(buffer)) on piisav.
  • Kas vormingu spetsifikaatorid on õiged.

Kokkuvõte

strftime() võimaldab paindlikult vormindada kuupäeva ja kellaaega. Seda saab kasutada logifailide ajatempli loomiseks või inimesele loetava kuupäeva kuvamiseks.

Järgmises jaotises vaatleme, kuidas aega liita ja lahutada – näiteks lisada 1 tund praegusele ajale või arvutada järgmise päeva kuupäev.

5. Aja liitmine ja lahutamine

C-keeles saab aega manipuleerida (liita või lahutada), et arvutada tulevasi või möödunud ajapunkte. Selles jaotises selgitame, kuidas kasutada time_t tüüpi ja funktsiooni mktime() aja arvutamiseks.

Aja liitmise ja lahutamise põhimõte

time_t tüüp esitab süsteemiaega sekundites, seega on võimalik teha lihtsaid arvutusi sekundite kaupa.

  • Liitmine: lisa sekundite arv, et arvutada tulevane aeg.
  • Lahutamine: lahuta sekundite arv, et arvutada möödunud aeg.

Kuidas aega manipuleerida

1. Otsene manipuleerimine time_t-ga

time_t väärtusele saab otseselt lisada või lahutada sekundeid.

Näide: ühe tunni võrra edasi
#include <stdio.h>
#include <time.h>

int main() {
    time_t now = time(NULL); // Praegune aeg
    time_t future = now + (60 * 60); // 1 tund hiljem (60 minutit × 60 sekundit)

    printf("Praegune aeg (sekundites): %ld\n", now);
    printf("1 tund hiljem (sekundites): %ld\n", future);

    return 0;
}
Väljundi näide
Praegune aeg (sekundites): 1700000000
1 tund hiljem (sekundites): 1700003600

See meetod sobib lihtsate sekundipõhiste arvutuste jaoks.

2. Manipuleerimine mktime()-i abil

mktime() võimaldab arvutada keerukamaid kuupäeva- ja ajaoperatsioone (nt järgmine päev või järgmine kuu).

Näide: järgmise päeva aja arvutamine
#include <stdio.h>
#include <time.h>

int main() {
    time_t now = time(NULL); // Praegune aeg
    struct tm *local = localtime(&now); // Teisenda lokaalseks ajaks

    local->tm_mday += 1; // Liigu ühe päeva võrra edasi
    time_t tomorrow = mktime(local); // Konverteeri tagasi time_t-ks

    printf("Praegune aeg: %s", ctime(&now));
    printf("Homme: %s", ctime(&tomorrow));

    return 0;
}
Väljundi näide
Praegune aeg: Sat Jan 12 15:30:45 2025
Homme: Sun Jan 13 15:30:45 2025

Märkus

  • mktime() korrigeerib automaatselt kuupäeva (nt 31. jaanuar + 1 päev = 1. veebruar).

Aja erinevuse arvutamine: difftime()

Kahe time_t väärtuse erinevust saab arvutada funktsiooniga difftime(). See tagastab sekundite arvu.

Näide: kahe aja vahe
#include <stdio.h>
#include <time.h>

int main() {
    time_t now = time(NULL); // Praegune aeg
    time_t future = now + (60 * 60 * 24); // 1 päev hiljem

    double diff = difftime(future, now); // Arvuta vahe

    printf("Praegune aeg: %s", ctime(&now));
    printf("1 päev hiljem: %s", ctime(&future));
    printf("Erinevus: %.0f sekundit\n", diff);

    return 0;
}
Väljundi näide
Praegune aeg: Sat Jan 12 15:30:45 2025
1 päev hiljem: Sun Jan 13 15:30:45 2025
Erinevus: 86400 sekundit

Aja manipuleerimise praktilised näited

1. Sündmuste ajastamine

Arvuta tulevane aeg ja käivita sündmused kindla intervalliga.

2. Ajalooliste andmete analüüs

Arvuta möödunud ajad, et filtreerida või analüüsida logisid või andmeid.

3. Tingimuslik käitumine kellaaja alusel

Võrdle praegust aega kindla võrdlusajaga ja muuda programmi loogikat vastavalt.

Olulised märkused

  • Ajavööndid: lokaalse aja puhul arvesta ajavööndi seadeid. Rahvusvahelistes rakendustes on soovitatav kasutada UTC-aega.
  • Liitmise ja lahutamise ühikud: sekundeid kasutatakse lihtsate arvutuste jaoks, kuid suuremate arvutuste puhul on parem kasutada struct tm-i.

Kokkuvõte

  • time_t võimaldab lihtsat liitmist ja lahutamist sekundite kaupa.
  • Keerulisemate arvutuste jaoks kasuta funktsiooni mktime().
  • Aja erinevuse arvutamiseks kasuta funktsiooni difftime().

Järgmises jaotises käsitleme C-keele ajakäsitlusega seotud 2038. aasta probleemi, et valmistuda tulevaste süsteemide arendamiseks.

6. Valmistumine 2038. aasta probleemiks

C-keeles kasutatakse laialdaselt time_t tüüpi süsteemiaja esitamiseks. Kuid selle tüübiga on seotud suur probleem, mida tuntakse kui „2038. aasta probleem“. Selles jaotises selgitame selle probleemi põhjuseid, mõjusid ja lahendusi.

Mis on 2038. aasta probleem?

2038. aasta probleem tekib, kuna paljud süsteemid, sealhulgas C-keel, kasutavad time_t tüüpi.

Põhjused

  • time_t on tavaliselt implementeeritud 32-bitise allkirjaga täisarvuna.
  • See salvestab sekundid alates 1. jaanuarist 1970 kell 00:00:00 (Unix epoch).
  • 32-bitine täisarv võib esitada maksimaalselt 2,147,483,647 väärtust.
  • See piir saavutatakse 19. jaanuaril 2038 kell 03:14:07 (UTC), mille järel toimub ületäitumine ning väärtus muutub negatiivseks.

Näide

#include <stdio.h>
#include <time.h>

int main() {
    time_t max_time = 2147483647; // Maksimaalne väärtus
    printf("2038. aasta piiraeg: %s", ctime(&max_time));

    time_t overflow_time = max_time + 1; // Ületäitumine
    printf("Ületäitumise järel: %s", ctime(&overflow_time));

    return 0;
}

Väljundi näide

2038. aasta piiraeg: Tue Jan 19 03:14:07 2038
Ületäitumise järel: Fri Dec 13 20:45:52 1901

Selles näites ajaväärtus „keritakse tagasi“ aastasse 1901.

2038. aasta probleemi mõju

See probleem võib mõjutada paljusid süsteeme:

  1. Pikaajalised taimerid ja ajastamised
  • Pärast 2038. aastat ei tööta ajapõhised taimerid ja ajastamised õigesti.
  1. Failisüsteemid
  • Failide ajatemplid (loomis- või muutmisajad) võivad muutuda valeks.
  1. Võrgusüsteemid
  • Autentimine ja logid, mis sõltuvad ajast, võivad anda vigu.
  1. Manussüsteemid
  • Vanemad seadmed ja infrastruktuur (nt ATM-id või POS-terminalid) võivad jääda ilma parandusteta.

Lahendused 2038. aasta probleemile

Probleemi vältimiseks saab rakendada järgmisi lähenemisi:

1. Üleminek 64-bitisele keskkonnale

  • Määratle time_t 64-bitise täisarvuna – see kõrvaldab praktiliselt probleemi.
  • 64-bitine time_t suudab esitada aega umbes 292 miljardit aastat.
Näide

Paljudes 64-bitistes keskkondades on probleem juba lahendatud vaikimisi.

2. Väliste teekide kasutamine

  • Võid kasutada paindlikumaid teeke nagu Boost.DateTime või Chrono.

3. Alternatiivsed ajavormingud

  • Kasuta stringe või kohandatud andmetüüpe. See on keerukam ja nõuab süsteemi ümberkujundamist.

Praktilised sammud

Serverite uuendamine

  • Kui kasutatakse 32-bitiseid süsteeme, tuleks need uuendada 64-bitistele OS-idele ja teekidele.

Olemasoleva koodi ülevaatus

  • Kontrolli, kus kasutatakse time_t-d, ja hinda ületäitumise riske.

Uute projektide arendamine

  • Soovitatav on arvestada vaikimisi 64-bitist ajakeskkonda.

Praegune olukord

Tänapäeval on paljud süsteemid juba üle läinud 64-bitisele keskkonnale, mistõttu uute projektide puhul probleem enamasti ei teki. Kuid vanemates manussüsteemides võib see endiselt eksisteerida.

Kokkuvõte

  • 2038. aasta probleem tekib, kui time_t on 32-bitine.
  • Parimad lahendused on 64-bitisele keskkonnale üleminek või kaasaegsete teekide kasutamine.
  • Vanemate süsteemide puhul tuleks varakult võtta tarvitusele abinõud.

Järgmises jaotises tutvustame praktilisi kasutusjuhtumeid, kus C-keeles ajaga töötamist rakendatakse päris süsteemides – näiteks logide ajatempleid ja sündmuste ajastamist.

7. Praktilised kasutusjuhud

C-keele ajafunktsioonid ei piirdu ainult praeguse aja hankimisega, vaid neid saab kasutada ka paljudes praktilistes süsteemides. Selles jaotises vaatleme mõningaid näiteid, kuidas ajakäsitlust kasutada reaalsetes olukordades. Need annavad ideid, kuidas oma programmi täiustada.

1. Ajatempli lisamine logidele

Süsteemi- ja vealogidesse lisatakse tavaliselt ajatempleid, et hiljem oleks lihtsam jälgida probleemide põhjuseid.

Näide: logi ajatempli salvestamine

#include <stdio.h>
#include <time.h>

void log_message(const char *message) {
    time_t now = time(NULL);
    struct tm *local = localtime(&now);

    char timestamp[80];
    strftime(timestamp, sizeof(timestamp), "%Y-%m-%d %H:%M:%S", local);

    printf("[%s] %s\n", timestamp, message);
}

int main() {
    log_message("Programm käivitati");
    log_message("Tekkis viga");
    log_message("Programm lõpetati");
    return 0;
}

Väljundi näide

[2025-01-12 15:30:45] Programm käivitati
[2025-01-12 15:30:46] Tekkis viga
[2025-01-12 15:30:47] Programm lõpetati

2. Sündmuste ajastamine

Kindla intervalliga toimingute käivitamine (nt iga 5 sekundi järel) on levinud mängudes või reaalajasüsteemides.

Näide: taimeri rakendamine

#include <stdio.h>
#include <time.h>
#include <unistd.h> // sleep() UNIX süsteemides

void perform_task() {
    printf("Sündmus käivitati\n");
}

int main() {
    time_t start = time(NULL);
    while (1) {
        time_t now = time(NULL);
        if (difftime(now, start) >= 5) { // iga 5 sekundi järel
            perform_task();
            start = now;
        }
        sleep(1); // vähenda CPU koormust
    }
    return 0;
}

Väljundi näide

Sündmus käivitati
(5 sekundi pärast)
Sündmus käivitati
(veel 5 sekundi pärast)
Sündmus käivitati

3. Tähtaegade haldamine

Kuupäeva arvutamist kasutatakse näiteks maksetähtaegade või tööde tähtaegade jälgimiseks.

Näide: maksetähtaja arvutamine

#include <stdio.h>
#include <time.h>

int main() {
    time_t now = time(NULL);
    struct tm *due_date = localtime(&now);

    due_date->tm_mday += 30; // 30 päeva hiljem
    mktime(due_date); // normaliseeri kuupäev

    char buffer[80];
    strftime(buffer, sizeof(buffer), "%Y-%m-%d", due_date);
    printf("Maksetähtaeg on: %s\n", buffer);

    return 0;
}

Väljundi näide

Maksetähtaeg on: 2025-02-11

4. Programmi täitmise aja mõõtmine

Optimeerimisel on oluline mõõta koodi täitmise kestust.

Näide: täitmisaja mõõtmine

#include <stdio.h>
#include <time.h>

int main() {
    clock_t start = clock();

    // Näidiskood (tsükkel)
    for (volatile long i = 0; i < 100000000; i++);

    clock_t end = clock();
    double elapsed = (double)(end - start) / CLOCKS_PER_SEC;

    printf("Täitmisaeg: %.3f sekundit\n", elapsed);
    return 0;
}

Väljundi näide

Täitmisaeg: 0.215 sekundit

5. Tingimuslik loogika kellaaja alusel

Programmi käitumist saab muuta sõltuvalt kellaajast (nt hommik vs pärastlõuna).

Näide: sõnum hommikul ja pärastlõunal

#include <stdio.h>
#include <time.h>

int main() {
    time_t now = time(NULL);
    struct tm *local = localtime(&now);

    if (local->tm_hour < 12) {
        printf("Tere hommikust!\n");
    } else {
        printf("Tere päevast!\n");
    }
    return 0;
}

Väljundi näide (hommikul)

Tere hommikust!

Väljundi näide (pärastlõunal)

Tere päevast!

Kokkuvõte

C-keele ajakäsitlus on kasulik logide, ajastamiste, kuupäevade arvutamise ja täitmisaja mõõtmise puhul. Need praktilised näited on abiks igapäevaste programmide kirjutamisel.

Järgmises jaotises käsitleme Korduma kippuvaid küsimusi (KKK), et vastata lugejate sagedastele kahtlustele.

8. Korduma kippuvad küsimused (KKK)

C-keeles aja töötlemisel tekib algajatel ja ka edasijõudnutel sageli küsimusi. Selles jaotises vastame levinud küsimustele, et süvendada arusaamist ajaga töötamisest.

K1. Kuidas hankida praegune aeg Jaapani ajavööndis (JST)?

V. Jaapani standardaeg (JST) on 9 tundi ees UTC-st. Funktsioon localtime() arvestab süsteemi ajavööndi seadistust, seega kui süsteem on seadistatud JST ajavööndile, tagastatakse aeg automaatselt Jaapani ajana.

Näide

#include <stdio.h>
#include <time.h>

int main() {
    time_t now = time(NULL);
    struct tm *local = localtime(&now);

    printf("Praegune Jaapani aeg: %d-%02d-%02d %02d:%02d:%02d\n",
           local->tm_year + 1900, local->tm_mon + 1, local->tm_mday,
           local->tm_hour, local->tm_min, local->tm_sec);

    return 0;
}

Märkus: veendu, et süsteemi ajavöönd on õigesti seadistatud.

K2. Kas on võimalik hankida aega millisekundites?

V. Standardne time.h ei toeta millisekundite hankimist. Kuid platvormipõhiste API-de abil (nt UNIX-is funktsioon gettimeofday()) saab millisekundi täpsuse.

Näide: millisekundite hankimine UNIX-is

#include <stdio.h>
#include <sys/time.h>

int main() {
    struct timeval tv;
    gettimeofday(&tv, NULL);

    printf("Praegune aeg: %ld sekundit ja %ld millisekundit\n",
           tv.tv_sec, tv.tv_usec / 1000);

    return 0;
}

Väljundi näide

Praegune aeg: 1700000000 sekundit ja 123 millisekundit

K3. Kuidas käsitleda suveaega (DST)?

V. Suveaja (Daylight Saving Time, DST) infot saab struct tm liikmest tm_isdst.

  • 1: suveaeg on aktiivne.
  • 0: suveaeg ei kehti.
  • -1: info pole saadaval.

Näide

#include <stdio.h>
#include <time.h>

int main() {
    time_t now = time(NULL);
    struct tm *local = localtime(&now);

    if (local->tm_isdst > 0) {
        printf("Hetkel kehtib suveaeg\n");
    } else {
        printf("Hetkel ei kehti suveaeg\n");
    }

    return 0;
}

K4. Kas strftime() abil saab näidata nädalapäeva eesti keeles?

V. strftime() arvestab lokaadi (keel ja piirkond). Funktsiooniga setlocale() saab määrata keeleks eesti keele, et näidata nädalapäeva eesti keeles.

Näide

#include <stdio.h>
#include <time.h>
#include <locale.h>

int main() {
    setlocale(LC_TIME, "et_EE.UTF-8");

    time_t now = time(NULL);
    struct tm *local = localtime(&now);

    char buffer[80];
    strftime(buffer, sizeof(buffer), "%Y. aasta %d. %B, %A", local);

    printf("Praegune kuupäev: %s\n", buffer);

    return 0;
}

Väljundi näide

Praegune kuupäev: 2025. aasta 12. jaanuar, pühapäev

Märkus: see sõltub, kas eesti lokaadid on süsteemi installitud.

K5. Kuidas käsitleda aega pärast 2038. aastat?

V. Probleemi vältimiseks kasuta 64-bitist time_t või alternatiivseid andmetüüpe. 64-bitistes süsteemides töötab time_t juba suuremate väärtustega.

Näide: 64-bitine time_t

#include <stdio.h>
#include <time.h>

int main() {
    time_t future = 2147483648; // väärtus üle 2038. aasta piiri
    printf("Aeg: %s", ctime(&future));
    return 0;
}

Väljundi näide

Aeg: Tue Jan 19 03:14:08 2038

Märkus: 32-bitises süsteemis ei pruugi see toimida.

K6. Miks programm ei kuva oodatud aega?

Peamised põhjused võivad olla:

  1. Vale ajavöönd: kontrolli süsteemi ajavööndi seadistust.
  2. Vigased väärtused struktuuris tm: kui mktime() teisendab vigase väärtuse, võib tulemus olla vale.
  3. Vananenud teegid: süsteemi ajateegid võivad vajada uuendamist.

Kokkuvõte

Selles KKK-jaotises vastasime levinud küsimustele C-keele ajafunktsioonide kohta. Katsetades koodinäiteid, saad paremini aru aja töötlemisest.

Järgmises jaotises võtame kogu artikli kokku ja kordame üle peamised punktid.

9. Kokkuvõte

Selles artiklis käsitlesime C-keele ajafunktsioone alates põhiteadmistest kuni praktiliste rakendusteni. Aja töötlemine on programmide üks olulisemaid funktsioone ja selle korrektne mõistmine võimaldab seda kasutada paljudes olukordades.

Õpitu kordamine

Peamised punktid, mida selles artiklis käsitlesime:

  1. Aja töötlemise alused C-keeles
  • Õppisime, kuidas kasutada time.h päisefaili süsteemiaja hankimiseks ja erinevateks operatsioonideks.
  • Tutvusime peamiste andmetüüpide (time_t, struct tm) ja funktsioonidega (time(), localtime(), mktime() jne).
  1. Praeguse aja hankimine ja kuvamine
  • Kasutasime funktsiooni time() aja hankimiseks ning teisendasime seda lokaalseks ajaks ja UTC-ks.
  • Kuvamiseks kasutasime ctime() ja strftime(), et muuta aeg inimesele loetavaks.
  1. Aja manipuleerimine ja arvutamine
  • Õppisime, kuidas liita ja lahutada aega sekundite kaupa time_t abil.
  • Kasutades mktime(), saime arvutada üle kuupäevade ja aegade.
  • difftime() abil arvutasime kahe aja erinevust.
  1. 2038. aasta probleemi mõistmine ja lahendamine
  • Selgitasime, kuidas 32-bitine time_t tekitab probleeme pärast 2038. aastat.
  • Pakkusime lahendusi, sealhulgas 64-bitise keskkonna kasutamist ja sobivate teekide rakendamist.
  1. Praktilised kasutusjuhud
  • Nägime näiteid logide ajatemplitest, sündmuste ajastamisest, tähtaegade arvutamisest ja täitmisaja mõõtmisest.
  1. KKK abil lahendasime levinud küsimused
  • Arutasime Jaapani aja hankimist, millisekundite täpsust, suveaja arvestamist ja 2038. aasta järgselt töötamist.

Järgmised sammud

Kui soovid teemat süvitsi uurida, soovitame:

  • Aja töötlemine mitmelõimelistes keskkondades – et tagada lõimes turvalised operatsioonid.
  • Väliste teekide kasutamine – näiteks Boost või Chrono teek paindlikumate funktsioonide jaoks.
  • Ajavööndite haldus – globaalses süsteemis on ajavööndite korrektne käsitlemine hädavajalik.

Lõppsõna

Aeg on iga programmi oluline element. Loodame, et see artikkel aitas sul paremini mõista C-keele ajafunktsioone ja annab tugeva aluse tõhusamate programmide loomiseks.

年収訴求