Time วันที่และเวลา ในภาษา C

ในบทนี้ คุณจะได้เรียนรู้เกี่ยวกับเวลาในภาษา C เราจะพูดถึงการอ่านค่าเวลาจากระบบ การวัดความแตกต่างของเวลา และการทำงานอื่นๆ เกี่ยวกับเวลา ในภาษา C มีฟังก์ชันจากไลบรารี่มาตรฐาน time.h สำหรับการทำงานกับเวลา นี่เป็นเนื้อหาในบทนี้

  • ระบบเวลาในคอมพิวเตอร์ Unix time
  • การแสดงวันที่และเวลาปัจจุบัน
  • โครงสร้างข้อมูลของเวลา struct tm
  • การแสดงเวลาใน Time zone อื่นๆ
  • การหาผลต่างของเวลา
  • การวัดประสิทธิภาพของโปรแกรม

เวลา (Time) คือการดำเนินไปอย่างต่อเนื่องของการดำรงอยู่และเหตุการณ์ต่างๆ ที่เกิดขึ้นอย่างไม่สามารถย้อนกลับได้ เวลาเดินทางจากอดีตถึงปัจจุบัน และไปยังอนาคต และในคอมพิวเตอร์ เวลาจะเริ่มนับจาก Unix epoch

Unix time

สิ่งแรกที่คุณควรรู้จักเกี่ยวกับเวลาในการเขียนโปรแกรมคอมพิวเตอร์ก็ Unix timestamp; Unix time เป็นระบบสำหรับอธิบายจุดของเวลาในคอมพิวเตอร์ มันคือจำนวนของวินาทีที่ผ่านไปโดยนับตั้งแต่ Unix epoch ซึ่งจุดนี้ของเวลานั้นเท่ากับวันที่ 1 มกราคม 1970 เวลา 00:00:00 UTC และ Unix time เริ่มต้นนับจากที่นี่

สำหรับตัวอย่างแรกในบทนี้ จะเป็นการอ่านค่าเวลาจากระบบในรูปแบบของ Unix time มาแสดงผลทางหน้าจอกับฟังก์ชันพื้นฐานอย่าง time

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

int main()
{
    time_t now;
    time(&now);
    printf("%ld seconds ", now);
    printf("since January 1, 1970 00:00:00 UTC");
    return 0;
}

นี่เป็นผลลัพธ์การทำงานของโปรแกรม

1595266585 seconds since January 1, 1970 00:00:00 UTC

ในตัวอย่าง เป็นการใช้งานฟังก์ชัน time เพื่อรับเอาเวลาปัจจุบันจากระบบและแสดงผลเวลาออกทางหน้าจอในรูปแบบของ Timestamp หรือ Unix time โดยค่าที่ส่งกลับมาจากฟังก์ชัน time นั้นมีประเภทข้อมูลเป็น time_t ซึ่งเป็นจำนวนของวินาทีที่ผ่านไปตั้งแต่ Unix epoch

time_t now;

ในคำสั่งแรก เราได้ประกาศตัวแปร now สำหรับเก็บค่าเวลาปัจจุบันก่อน โดยตัวแปรนี้มีประเภทข้อมูลเป็น time_t มันเป็นประเภทข้อมูลที่ถูกกำหนดขึ้นในไลบรารี่ time.h มันสามารถใช้สำหรับเก็บเวลาในจุดใดๆ

time(&now);

หลังจากนั้นเราเรียกใช้ฟังก์ชัน time โดยการส่งค่าที่อยู่ (&now) หรือพอบยน์เตอร์ของตัวแปร now เป็นพารามิเตอร์ของฟังก์ชัน และในตอนนี้ค่าของเวลาปัจจุบันจะถูกเก็บในตัวแปร now

printf("%d seconds ", now);

จากนั้นเราแสดงผลค่าของเวลาปัจจุบันออกทางหน้าจอ เราสามารถแปลงค่าของ time_t ไปเป็นตัวเลขได้โดยตรง โดยการใช้ Specifier การแสดงผลแบบตัวเลข %d

อีกรูปแบบหนึ่งสำหรับการรับเอาเวลาปัจจุบันด้วยฟังก์ชัน time คุณสามารถส่งค่าพารามิเตอร์เป็น NULL เข้าไปยังฟังก์ชันได้ และค่าที่ส่งกลับมาจะเป็น time_t นี่เป็นตัวอย่าง

time_t now = time(NULL);

ในคำสั่งนี้ให้ผลลัพธ์เหมือนกับในตัวอย่างด้านบน ในกรณีที่คุณต้องการรับค่าปัจจุบัน แค่ส่ง NULL เข้าไปยังฟังก์ชัน

การแสดงวันที่และเวลาปัจจุบัน

Timestamp หรือ Unix time เป็นรูปแบบของเวลาที่ใช้สำหรับคอมพิวเตอร์ และเพื่อให้มนุษย์สามารถเข้าใจเวลาดังกลาวได้ง่ายขึ้น เราสามารถแปลงมันไปยังรูปแบบเวลาของปฏิทินเหมือนที่เราคุ้นเคยในชีวิตประจำวันได้ โดยการใช้ฟังก์ชัน ctime นี่เป็นตัวอย่าง

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

int main()
{
    time_t now;

    time(&now);
    printf("The current local time is: %s", ctime(&now));
    printf("The current timestamp is: %ld", now);
    return 0;
}

นี่เป็นผลลัพธ์การทำงานของโปรแกรม

The current local time is: Tue Jul 21 01:19:45 2020
The current timestamp is: 1595269185

ในตัวอย่าง เราได้แปลงเวลาจาก Unix time เป็นรูปแบบเวลาของปฏิทินโดยการใช้ฟังก์ชัน ctime ฟังก์ชันนี้ส่งค่ากลับเป็น String ของเวลาปัจจุบันในรูปแบบที่เราสามารถอ่านเข้าใจได้ง่าย มันรับพารามิเตอร์เป็นที่อยู่ของตัวแปร now เพื่อทำงาน สังเกตเครื่องหมาย & หน้าตัวแปรในตอนเรียกฟังก์ชัน

โครงสร้างข้อมูลของเวลา struct tm

โครงสร้างข้อมูลของเวลาหรือ struct tm นั้นเป็นประเภทข้อมูลที่ถูกกำหนดไว้ในไลบรารี่ time.h มันเป็นโครงสร้างข้อมูลที่เก็บองประกอบต่างๆ ของเวลาแยกออกจากกัน นี่จะทำให้เราสามารถเข้าถึงบางส่วนของเวลาได้ เช่น วันของสัปดาห์ เป็นต้น

เนื่องจากเวลาแบบ time_t นั้นเก็บค่าเป็น Timestamp จะเป็นยังไงถ้าเราต้องการข้อมูลเพิ่มเติมเกี่ยวกับเวลา เช่น เราต้องการทราบว่าวันในสัปดาห์คือวันอะไร เพื่อเข้าถึงข้อมูลดังกล่าว เราสามารถแปลง time_t เป็นโครงสร้างข้อมูลของเวลาหรือ struct tm ได้ นี่เป็นตัวอย่าง

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

int main()
{
    time_t rawtime;
    struct tm * local;

    // Get current time
    time(&rawtime);
    // Convert to time structure
    local = localtime(&rawtime);

    printf("The current local time is: %s", ctime(&rawtime));
    printf("The current timestamp is: %ld\n", rawtime);

    // Accessing time components
    printf("Week day: %d\n", local->tm_wday);
    printf("Year: %d\n", local->tm_year);
    printf("Month: %d\n", local->tm_mon);
    printf("Day: %d\n", local->tm_mday);
    printf("Hour: %d\n", local->tm_hour);
    printf("Minute: %d\n", local->tm_min);
    printf("Second: %d\n", local->tm_sec);
    return 0;
}

นี่เป็นผลลัพธ์การทำงานของโปรแกรม

The current local time is: Tue Jul 21 01:56:15 2020
The current timestamp is: 1595271375
Week day: 2
Year: 120
Month: 6
Day: 21
Hour: 1
Minute: 56
Second: 15

ในตัวอย่าง เราได้แสดงเวลาปัจจุบันและค่า Timestamp ออกมาทางหน้าจอเหมือนกับในตัวอย่างก่อนหน้า แต่สิ่งที่เพิ่มเข้ามาในตัวอย่างนี้ เราสามารถเข้าถึงส่วนประกอบต่างๆ ของเวลาที่ต้องการได้จากโครงสร้างของเวลา struct tm ในตัวแปร local

struct tm * local;

ในคำสั่งนี้เป็นการประกาศตัวแปรพอยน์เตอร์สำหรับ struct tm ที่ชื่อว่า local สำหรับเก็บส่วนประกอบของเวลา

// Get current time
time(&rawtime);
// Convert to time structure
local = localtime(&rawtime);

เรารับค่าเวลาปัจจุบันมาเก็บไว้ในตัวแปร rawtime และจากนั้นแปลงเวลาปัจจุบันเป็นโครงสร้างข้อมูลของเวลาด้วยฟังก์ชัน localtime และเก็บค่าไว้ในตัวแปรพอยน์เตอร์ local ที่เราได้ประกาศไปก่อนหน้า

printf("Week day: %d\n", local->tm_wday);
printf("Year: %d\n", local->tm_year);
printf("Month: %d\n", local->tm_mon);
printf("Day: %d\n", local->tm_mday);
printf("Hour: %d\n", local->tm_hour);
printf("Minute: %d\n", local->tm_min);
printf("Second: %d\n", local->tm_sec);

ตอนนี้เราสามารถเข้าถึงส่วนประกอบต่างๆ ของเวลาผ่านทางตัวแปร local ได้ ยกตัวอย่างเช่น tm_wday นั้นเป็นวันของสัปดาห์ที่มีค่าตั้งแต่ 0 - 6 ซึ่งหมายถึงวันอาทิตย์ถึงวันเสาร์ ส่วน tm_year tm_mon และ tm_mday เป็นค่าของปี เดือน และวันของเดือน ตามลำดับ และที่เหลือเป็นการเข้าถึงส่วนประกอบของเวลา ชั่วโมง นาที และวินาที

จะเห็นว่าค่าของปีนั้นแสดงเป็น 120 นั่นเป็นเพราะว่าปีในภาษา C นั้นจะเริ่มนับจากปี 70 ซึ่งหมายถึงปี 1970 ดังนั้น 120 จึงหมายถึงปี 2020 (1900 + 120) นั่นเอง ดังนั้นในการแปลงไปเป็นปีจริงๆ ในปฏิทิน เราต้องบวก 1900 เข้าไปด้วยเสมอ เหมือนกับในตัวอย่างข้างล่างนี้

printf("Year: %d\n", 1900 + local->tm_year);

และในตอนนี้เราจะได้รับค่าปีที่เหมือนกับในปฏิทินแล้ว

ฟังก์ชัน localtime จะแปลงเวลาเป็นโครงสร้างข้อมูลของเวลาในเขตของเวลาท้องถิ่นที่คุณอยู่ (อ้างอิงจากคอมพิวเตอร์ของคุณ) ซึ่งในประเทศไทยนั้นมีเขตเวลาเป็น +07:00

การแสดงเวลาใน Time zone อื่นๆ

อีกหนึ่งฟังก์ชันสำหรับแปลงเวลาเป็น struct tm คือฟังก์ชัน gmtime มันใช้สำหรับแปลงเวลาไปยังโครงสร้างข้อมูลของเวลาในเขตเวลา GTM หรือ UTC time ซึ่งเป็นเขตเวลามาตรฐานกรีนิช ซึ่งเรามักจะใช้ฟังก์ชันนี้เมื่อเราต้องการเวลาในเขตต่างๆ ของโลก โดยใช้เขตเวลา GTM เป็นเขตเวลาอ้างอิงหลัก

ในตัวอย่างต่อมา เราจะเขียนโปรแกรมสำหรับแสดงเวลาตามสถานที่ต่างๆ ของโลก จากเขตเวลาที่สถานที่เหล่านั่นอยู่โดยการใช้งานฟังก์ชัน gmtime นี่เป็นตัวอย่าง

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

#define PST (-7)
#define UTC (0)
#define THA (+7)

int main()
{
    time_t rawtime;
    struct tm * gmt;

    time (&rawtime);

    gmt = gmtime(&rawtime);

    puts("Current time around the World:");
    printf("Sacramento, CA (U.S.)  : %2d:%02d\n", (gmt->tm_hour + PST) % 24, gmt->tm_min);
    printf("London (England)       : %2d:%02d\n", (gmt->tm_hour + UTC) % 24, gmt->tm_min);
    printf("Bangkok (Thailand)     : %2d:%02d\n", (gmt->tm_hour + THA) % 24, gmt->tm_min);
    return 0;
}

นี่เป็นผลลัพธ์การทำงานของโปรแกรม

Current time around the World:
Sacramento, CA (U.S.)  : 12:37
London (England)       : 19:37
Bangkok (Thailand)     :  2:37

ในตัวอย่าง เราได้สร้างโปรแกรมนาฬิกาเพื่อแสดงเวลาที่ตำแหน่งต่างๆ ในโลกได้แก่ เมืองซาคราเมนโตที่สหรัฐอเมริกา เมืองลอนดอนที่ประเทศอังกฤษ และกรุงเทพที่ประเทศไทย

#define PST (-7)
#define UTC (0)
#define THA (+7)

ในตอนแรก เราได้ประกาศค่าคงที่เพื่อเก็บเขตเวลาของสถานที่ต่างๆ โดยอ้างอิงจากเขตเวลา GMT ซึ่ง +7 ในตัวแปร THA หมายความว่าเวลาในประเทศไทยนั้นเร็วกว่าเวลาที่เขตเวลามาตรฐานกรีนิช (GMT) เป็นเวลา 7 ชั่วโมง ส่วนในตัวแปร PST ที่มีค่าเป็นลบหมายความว่าเวลาช้ากว่าเขตเวลามาตรฐานกรีนิช 7 ชั่วโมง

gmt = gmtime(&rawtime);

จากนั้นเราแปลงเวลาปัจจุบันเป็นเวลาในเวลามาตรฐานกรีนิช และเก็บไว้ในตัวแปร gmt

printf("Sacramento, CA (U.S.)  : %2d:%02d\n", (gmt->tm_hour + PST) % 24, gmt->tm_min);
printf("London (England)       : %2d:%02d\n", (gmt->tm_hour + UTC) % 24, gmt->tm_min);
printf("Bangkok (Thailand)     : %2d:%02d\n", (gmt->tm_hour + THA) % 24, gmt->tm_min);

ในการที่จะแปลงเวลาในเขตเวลามาตรฐานกรีนิช ไปยังเขตเวลาอื่นๆ เราได้ทำการบวกจำนวนชั่วโมงจากค่าเขตของเวลาของสถานที่เหล่านี้เข้าไปยัง tm_hour เพื่อรับเอาชั่วโมงในเขตเวลานั้นๆ ออกมา

ในตัวอย่างก่อนหน้า เราได้สร้างโครงสร้างของเวลาจากฟังก์ชัน localtime และ gmtime อย่างไรก็ตาม เราสามารถสร้างโครงสร้างเวลาและกำหนดส่วนประกอบต่างๆ ด้วยตัวเองได้ ยกตัวอย่างเช่น เราต้องการสร้างโครงสร้างของเวลา และตัวแปรเวลาสำหรับวันเกิดของเรา เพื่อทำมาใช้งานในการเขียนโปรแกรม

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

int main()
{
    time_t birthdate;
    struct tm bd;

    // Set time components to zero
    bd.tm_hour = 0;
    bd.tm_min = 0;
    bd.tm_sec = 0;

    // Set date of birth
    bd.tm_year = 88;  // 1988
    bd.tm_mon = 2;    // March
    bd.tm_mday = 12;  // 12

    // Convert struct tm to time_t
    birthdate = mktime(&bd);

    printf("My birthday is %s", asctime(&bd));
    printf("It's %d seconds since I was born\n", birthdate);
    return 0;
}

นี่เป็นผลลัพธ์การทำงานของโปรแกรม

My birthday is Sat Mar 12 00:00:00 1988
It's 574102800 seconds since I was born

ในตัวอย่าง เราสร้างโครงสร้างข้อมูลของเวลาด้วยตัวเอง หลังจากนั้นแปลงโครงสร้างข้อมูลดังกล่าวเป็น Timestamp และแสดงผลออกทางหน้าจอ

time_t birthdate;
struct tm bd;

ในตอนแรก เราประกาศสองตัวแปรที่ว่างเปล่าสำหรับเก็บค่าของเวลาและโครงสร้างของเวลา

bd.tm_hour = 0;
bd.tm_min = 0;
bd.tm_sec = 0;

เนื่องจากเราสนใจแค่วันเกิด ดังนั้นเรากำหนดส่วนประกอบของเวลาทั้งหมดเป็นศูนย์

bd.tm_year = 88;  // 1988
bd.tm_mon = 2;    // March
bd.tm_mday = 12;  // 12

เรากำหนดวัน เดือน ปีเกิดให้กับโครงสร้างของเวลา bd

อย่างที่เราบอกไปแล้วก่อนหน้าว่า ในภาษา C ค่าของปีในโครงสร้างข้อมูลจะเริ่มต้นจาก 70 ซึ่งหมายถึงปี 1970 ดังนั้นถ้าหากเราต้องการกำหนดปีเป็น 1988 เราต้องกำหนดค่าให้กับ bd.tm_year เป็น 88 โดยการลบปีจริงออกจาก 1900 เช่น 1988 - 1900 = 88 ซึ่งนี่เป็นสิ่งที่คุณจะต้องรู้เกี่ยวกับการกำหนดปีให้กับโครงสร้างข้อมูลของเวลา

birthdate = mktime(&bd);

จากนั้นเราแปลงโครงสร้างของเวลาที่สร้างขึ้นให้เป็นเวลาในรูปแบบ time_t ด้วยฟังก์ชัน mktime โดยฟังก์ชันนี้รับพารามิเตอร์เป็นพอยน์เตอร์ของ bd และส่งค่ากลับเป็นเวลาและเก็บไว้ในตัวแปร birthdate

printf("My birthday is %s", asctime(&bd));

เราสามารถแปลงโครงสร้างของเวลาเป็น String ได้ด้วยฟังก์ชัน asctime ซึ่งฟังก์ชันนี้มีการทำงานเหมือนกับฟังก์ชัน ctime ที่คุณได้เรียนรู้ไปก่อนหน้า แต่มันรับพารามเตอร์เป็นโครงสร้างของเวลาแทน ซึ่งมีค่าเหมือนกับเราเรียกใช้คำสั่งนี้ ctime(mktime(&bd))

printf("It's %d seconds since I was born\n", birthdate);

สุดท้ายเราได้แสดงข้อความออกมาทางหน้าจอว่ามันได้ผ่านมากี่วินาทีแล้วตั้งแต่ที่เราเกิดมา คุณสามารถนำตัวแปร birthdate ไปใช้กับฟังก์ชันอืนๆ ที่สามารถใช้ร่วมกันได้ เช่น localtime หรือ gmtime ทีคุณได้เรียนรู้ไปในตัวอย่างก่อนหน้านี้

สำหรับสมาชิกในโครงสร้างข้อมูล struct tm ทั้งหมดสามารถดูได้ที่ http://www.cplusplus.com/reference/ctime/tm/

การหาผลต่างของเวลา

ในการเขียนโปรแกรม เราอาจจะต้องการรู้ว่าเวลาในจุดที่หนึ่งนั้นห่างจากจุดที่สองเท่าไหร่ ยกตัวอย่าง เช่น คุณอาจจะต้องการทราบว่ามัตั้แต่วันที่ December 30, 1980 จนถึงปัจจุบุบันนั้นเวลาผ่านมากี่วินาทีแล้ว ในภาษา C เราสามารถหาผลต่างระหว่างเวลาสองจุดได้โดยการใช้ฟังก์ชัน difftime นี่เป็นตัวอย่าง

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

int main()
{
    struct tm timeinfo;
    timeinfo.tm_hour = 0;
    timeinfo.tm_min = 0;
    timeinfo.tm_sec = 0;
    timeinfo.tm_year = 80;  // 1980
    timeinfo.tm_mon = 11;   // December
    timeinfo.tm_mday = 30;  // 30

    time_t beginning = mktime(&timeinfo);
    time_t end = time(NULL);

    double diff = difftime(end, beginning);
    printf("BEGIN:\t\t%d\t%s", beginning, ctime(&beginning));
    printf("END\t\t%d\t%s", end, ctime(&end));
    printf("%.lf seconds passed since December 30, 1980", diff);
    return 0;
}

นี่เป็นผลลัพธ์การทำงานของโปรแกรม

BEGIN   346957200       Tue Dec 30 00:00:00 1980
END     1595640258      Sat Jul 25 08:24:18 2020
1248683058 seconds passed since December 30, 1980

ในตัวอย่าง เป็นโปรแกรมสำหรับหาผลต่างของเวลาระหว่างวันที่ December 30, 1980 และเวลาปัจจุบัน (ตอนที่โปรแกรมนี้ถูกรัน) โดยการใช้ฟังก์ชัน difftime ฟังก์ชันนี้รับค่าสองพารามิเตอร์ซึ่งเป็นข้อมูลประเภท time_t ที่ต้องการหาผลต่างของเวลา และส่งค่ากลับเป็น double ซึ่งเป็นผลลต่างของเวลาในหน่วยวินาที

time_t beginning = mktime(&timeinfo);
time_t end = time(NULL);

double diff = difftime(end, beginning);

คุณสามารถสร้างเวลาที่ต้องการจากโครงสร้างของเวลาในตัวแปร timeinfo ซึ่งเรากำหนดวันและเวลาเป็น December 30, 1980 เวลา 00:00:00 และแปลงโครงสร้างของเวลาดังกล่าวให้เป็น time_t ก่อนที่จะนำมาหาผลต่างด้วยฟังก์ชัน difftime

ในตัวอย่างนี้ เราได้ผลต่างของเวลาเป็น 1,248,683,058 หรือประมาณ 1.2 พันล้านวินาที อย่างไรก็ตาม สำหรับมนุษย์นั้นมันอยากที่จะเข้าใจว่าเวลานั้นผ่านมานานแค่ไหนแล้ว ในตัวอย่างต่อไป เราจะสร้างฟังก์ชันมาแปลงเวลาให้แสดงเป็นข้อความของเวลาที่ผ่านไปแทน นี่จะทำให้เราสามารถเข้าใจได้ง่ายขึ้น

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

char* time_ago(long time)
{
    int year = time / 31557600;
    int month = (time % 31557600) / 2592000;
    int day = (time % 2592000) / 86400;
    int hour = (time % 86400) / 3600;
    int minute = (time % 3600) / 60;
    int second = time % 60;

    char format[100] = "%d years %d months %d days %d hours %d mins %d seconds";
    char * buffer = malloc(100);

    sprintf(buffer, format, year, month, day, hour, minute, second);
    return buffer;
}

int main()
{
    struct tm timeinfo;
    timeinfo.tm_hour = 0;
    timeinfo.tm_min = 0;
    timeinfo.tm_sec = 0;
    timeinfo.tm_year = 80;  // 1980
    timeinfo.tm_mon = 11;   // December
    timeinfo.tm_mday = 30;  // 30

    time_t beginning = mktime(&timeinfo);
    time_t end = time(NULL);

    double diff = difftime(end, beginning);
    char* passed = time_ago((long) diff);

    printf("BEGIN\t%d\t%s", beginning, ctime(&beginning));
    printf("END\t%d\t%s", end, ctime(&end));
    printf("Time passed since December 30, 1980\n");
    printf("%s ago", passed);
    return 0;
}

นี่เป็นผลลัพธ์การทำงานของโปรแกรม

BEGIN   346957200       Tue Dec 30 00:00:00 1980
END     1595641765      Sat Jul 25 08:49:25 2020
Time passed since December 30, 1980
39 years 6 months 22 days 8 hours 49 mins 25 seconds ago

ในตัวอย่างนี้ เราได้ใช้โค้ดจากในตัวอย่างก่อนหน้า แต่สิ่งที่เพิ่มเติ่มเข้ามาก็คือเราได้สร้างฟังก์ชัน time_ago สำหรับแปลงค่าวินาทีให้เป็นข้อความบอกเวลาที่ผ่านไปจากหน่วยของเวลาที่ใหญ่ที่สุด นั่นก็คือปี เดือน วัน ชั่วโมง นาที และวินาที ตามลำดับ

int year = time / 31557600;
int month = (time % 31557600) / 2592000;
int day = (time % 2592000) / 86400;
int hour = (time % 86400) / 3600;
int minute = (time % 3600) / 60;
int second = time % 60;

ในฟังก์ชัน time_ago เราได้แยกเอาหน่วยต่างๆ ของเวลาออกจากวินาทีทั้งหมด เพื่อแยกเอาค่าปีออกมา เราได้นำค่าวินาทีที่ผ่านไปหารด้วยจำนวนวินาทีทั้งหมดในหนึ่งปีซึ่งก็คือ 31557600 แล้วเก็บไว้ในตัวแปร year จากนั้นเพื่อหาค่าของเดือน เอาเศษที่เหลือจากวินาทีในหนึ่งปีหารด้วยวินาทีทั้งหมดในหนึ่งเดือนซึ่งก็คือ 2592000 และเก็บในตัวแปร month

เช่นเดียวกันเพื่อหาค่าของวันในตัวแปร day เอาเศษที่เหลือจากวินาทีในหนึ่งเดือนหารด้วยวินาทีทั้งหมดในหนึ่งวันซึ่งก็คือ 86400 และทำเช่นนี้ไปเรื่อยๆ จนถึงวินาที โดยค่าของวินาทีก็คือเศษที่เหลือของเวลาในหนึ่งนาทีหรือ 60 วินาทีนั่นเอง

char format[100] = "%d years %d months %d days %d hours %d mins %d seconds";
char * buffer = malloc(100);

sprintf(buffer, format, year, month, day, hour, minute, second);

หลังจากที่เราได้ส่วนต่างๆ ของเวลา เรานำค่าเหล่านั้นมาสร้างเป็น String ด้วยฟังก์ชัน sprintf โดยมันจะทำการสร้าง String จากรูปแบบที่กำหนดและเขียนใส่ในตัวแปร buffer และเราส่งค่านี้กลับไป

การจับเวลาเพื่อวัดประสิทธิภาพของโปรแกรม

ในตัวอย่างก่อนหน้า เราได้สร้างเวลาจาก time_t ซึ่งข้อมูลประเภทนี้เก็บเวลาได้ละเอียดสุดถึงแค่ในหน่วยวินาทีเท่านั้น จะเป็นยังไงถ้าหากเราต้องการค่าของเวลาที่ละเอียดกว่านั้น ยกตัวอย่างเช่น เราต้องการจับเวลาการทำงานของโปรแกรมที่สามารถบอกความต่างของเวลาได้ถึงระดับมิลลิวินาที เราจะมาดูว่าทำอย่างไรในภาษา C

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

int frequency_of_primes(int n)
{
    int count = 0;
    for (int i = 2; i <= n; i++) {
        int is_prime = 1;
        for (int j = 2; j <= i; j++) {
            if (i % j == 0 && j != i) {
                is_prime = 0; break;
            }
        }
        if (is_prime == 1) count++;
    }
    return count;
}

int main()
{
    clock_t start, end;
    int prime_count;

    start = clock();
    prime_count = frequency_of_primes(100000);
    end = clock();

    float sec = (float)(end - start) / CLOCKS_PER_SEC;

    printf("There are %d prime numbers between 1 - 100000\n", prime_count);
    printf("%d clocks ticked\n", end - start);
    printf("Calculation finished in %f seconds\n", sec);
    return 0;
}

นี่เป็นผลลัพธ์การทำงานของโปรแกรม

There are 9592 prime numbers between 1 - 100000
1828 clocks ticked
Calculation finished in 1.828000 seconds

ในตัวอย่าง เป็นโปรแกรมสำหรับหาว่าจำนวนเฉพาะทีี่มีค่าระหว่าง 1 - 100000 นั้นมีจำนวนกี่ตัว เนื่องจากเราต้องการทราบเวลาการคำนวณอย่างละเอียดในหน่วยมิลลิวินาที ดังนั้นเราจึงใช้ฟังก์ชัน clock และค่าคงที่ CLOCKS_PER_SEC แทนฟังก์ชันทั้งหมดที่เราเคยใช้ไปก่อนหน้า

int frequency_of_primes(int n)
{
    ...
    return count;
}

เราได้สร้างฟังก์ชัน frequency_of_primes สำหรับคำนวณและตรวจสอบว่าจำนวนเฉพาะระหว่าง 1 - n นั้นมีจำนวนเท่าไหร่ โดยในตัวอย่างของเรานั้นได้ส่งค่า n เป็น 100000 เข้ามายังฟังก์ชัน ภายในฟังก์ชันนี้ใช้อัลกรอริทึมพื้นฐานสำหรับตรวจสอบว่าตัวเลขเป็นจำนวนเฉพาะหรือไม่ และสุดท้ายเราส่งค่ากลับเป็นจำนวนของจำนวนเฉพาะทั้งหมดที่นับได้กลับไป

start = clock();
prime_count = frequency_of_primes(100000);
end = clock();

นี่เป็นโค้ดส่วนหลักที่เราต้องการเน้นในตัวอย่างนี้ เราต้องการทราบว่าการทำงานของฟังก์ชัน frequency_of_primes นั้นใช้เวลาไปเท่าไหร่ เราได้เรียกใช้ฟังก์ชัน clock ซึ่งส่งค่ากลับเป็นเวลาของ CPU ซึ่งมีหน่วยเป็น trick ก่อนจุดที่ต้องการวัดความแตกต่างของเวลา

float sec = (float)(end - start) / CLOCKS_PER_SEC;

หลังจากเราได้เวลาการทำงานของ CPU ก่อนและหลังแล้ว เราหาผลต่างของเวลาโดยการนำเวลาเริ่มต้นและเวลาสิ้นสุดมาลบกัน จากนั้นหารค่าที่ได้ด้วยจำนวน CLOCK ต่อวินาที (CLOCKS_PER_SEC) ซึ่งค่านี้เป็นค่าคงที่ที่สามารถเปลี่ยนแปลงไปตามสภาพแวดล้อมการทำงานของโปรแกรม

ในตอนี้เราจะได้ค่าของเวลาที่ผ่านไปในหน่วยวินาทีซึ่งมีความละเอียดในระดับมิลิวินาทีในตัวแปร sec และในกรณีที่เราต้องการค่าในหน่วยมิลลิวินาที คูณผลลัพธ์ที่ได้ด้วย 1000 ยกตัวอย่างเช่น

long millisec = ((float)(end - start) / CLOCKS_PER_SEC) * 1000;

ฟังก์ชัน clock ไม่ได้ส่งค่ากลับเป็นเวลาปัจจุบันของระบบ แต่มันส่งค่ากลับเป็นเวลา (CPU trick) ตั้งแต่ที่โปรแกรมเริ่มทำงาน โดยที่ในหนึ่งวินาทีนั้น CPU จะทำการ trick โดยมีค่าอยู่ที่ CLOCKS_PER_SEC

ในบทนี้ คุณได้เรียนรู้เกี่ยวกับเวลาและวันที่พื้นฐานในภาษา C เราได้แนะนำให้คุณรู้จักเกี่ยวกับระบบเวลาในคอมพิวเตอร์ซึ่งก็คือ Unit time การแสดงผลเวลาปัจจุบัน การใช้งานโครงสร้างของเวลา การหาผลต่างของเวลา และ การวัดประสิทธิภาพการทำงานของโปรแกรมในระดับมิลลิวินาที