Lấy thời gian hiện tại trong C++ như nào?
Truy xuất thời gian hiện tại là một nhu cầu quan trọng trong hầu hết các ứng dụng phần mềm hiện đại. Từ việc ghi nhật ký sự kiện, tính toán thời gian thực thi, đến việc lên lịch các tác vụ, xử lý thời gian đều đóng vai trò thiết yếu. Trong C++, chúng ta có nhiều cách tiếp cận để làm việc với thời gian, mỗi cách đều có những ưu và nhược điểm riêng.
Có hai phương pháp chính để xử lý thời gian trong C++:
- Thư viện truyền thống `time.h` (hoặc `ctime`): Đây là phương pháp cổ điển, có từ thời C và được kế thừa trong C++.
- Thư viện hiện đại `chrono`: Được giới thiệu từ chuẩn C++11, cung cấp các tính năng xử lý thời gian mạnh mẽ và linh hoạt hơn.
Trong bài viết này, chúng ta sẽ tìm hiểu chi tiết cả hai phương pháp, từ cơ bản đến nâng cao, giúp bạn nắm vững kỹ năng xử lý thời gian trong C++.

Tại sao cần biết cách xử lý thời gian?
Trước khi đi vào chi tiết kỹ thuật, hãy hiểu tại sao việc xử lý thời gian lại quan trọng:
- Ghi log và debug: Ghi lại thời điểm xảy ra các sự kiện quan trọng giúp theo dõi và gỡ lỗi ứng dụng.
- Đo hiệu suất: Đo thời gian thực thi giúp tối ưu hóa code và phát hiện các điểm nghẽn.
- Tạo timestamp: Đánh dấu thời gian cho dữ liệu, tập tin hoặc giao dịch.
- Lên lịch và hẹn giờ: Thực thi các tác vụ theo lịch cụ thể hoặc sau một khoảng thời gian.
- Tính toán thời gian: Tính tuổi, thời hạn, thời gian còn lại, v.v.
Với một người mới học lập trình, việc nắm vững cách xử lý thời gian sẽ giúp bạn xây dựng các ứng dụng thực tế và chuyên nghiệp hơn.
Phương pháp 1: Sử dụng thư viện time.h
Thư viện time.h
(trong C++, thường được sử dụng thông qua ctime
) là phương pháp truyền thống để làm việc với thời gian. Đây là lựa chọn phù hợp cho người mới bắt đầu vì cú pháp đơn giản và dễ hiểu.
Các khái niệm cơ bản trong time.h
Trước khi xem code, hãy làm quen với một số khái niệm chính:
- time_t: Kiểu dữ liệu số nguyên đại diện cho số giây kể từ “epoch” (00:00:00 UTC, ngày 1 tháng 1 năm 1970).
- struct tm: Cấu trúc chứa các thành phần thời gian riêng biệt (giờ, phút, giây, ngày, tháng, năm, v.v.).
- Epoch time: Điểm tham chiếu thời gian trong hệ thống máy tính, thường là 00:00:00 UTC ngày 1/1/1970.
Ví dụ cơ bản
#include <iostream>
#include <ctime>
using namespace std;
int main() {
// Lấy thời gian hiện tại dưới dạng số giây kể từ epoch
time_t now = time(0);
// Chuyển đổi sang dạng chuỗi dễ đọc
char* dt = ctime(&now);
cout << "Current date time: " << dt;
return 0;
}
// Current date time: Sun Apr 6 14:29:05 2025
Đoạn code trên sẽ hiển thị thời gian hiện tại dưới dạng chuỗi như: “Sun Apr 6 14:29:05 2025”.
Truy cập chi tiết các thành phần của thời gian
Để truy cập và hiển thị từng thành phần của thời gian (giờ, phút, giây, ngày, tháng, năm), chúng ta sử dụng hàm localtime()
để chuyển đổi time_t
sang cấu trúc struct tm
:
#include <iostream>
#include <ctime>
#include <iomanip> // Cho setfill và setw
using namespace std;
int main() {
// Lấy thời gian hiện tại
time_t now = time(0);
// Chuyển đổi sang dạng local time
tm* ltm = localtime(&now);
// In từng thành phần của thời gian với định dạng đẹp
cout << "Date: " << setfill('0') << setw(2) << ltm->tm_mday << "/"
<< setfill('0') << setw(2) << (1 + ltm->tm_mon) << "/"
<< (1900 + ltm->tm_year) << endl;
cout << "Time: " << setfill('0') << setw(2) << ltm->tm_hour << ":"
<< setfill('0') << setw(2) << ltm->tm_min << ":"
<< setfill('0') << setw(2) << ltm->tm_sec << endl;
// Thông tin về ngày trong tuần
string weekdays[] = {"Sunday", "Monday", "Tuesday", "Wednesday",
"Thursday", "Friday", "Saturday"};
cout << "Day of week: " << weekdays[ltm->tm_wday] << endl;
// Ngày thứ bao nhiêu trong năm (1-366)
cout << "Day of year: " << ltm->tm_yday + 1 << endl;
return 0;
}
Lưu ý quan trọng về struct tm
Khi làm việc với struct tm
, cần chú ý một số điểm đặc biệt:
- tm_year: Là số năm kể từ 1900, cần cộng thêm 1900 để có năm hiện tại.
- tm_mon: Chạy từ 0 đến 11, cần cộng thêm 1 để có tháng thông thường (1-12).
- tm_wday: Ngày trong tuần, từ 0 (Chủ nhật) đến 6 (Thứ bảy).
- tm_yday: Ngày trong năm, từ 0 đến 365.
Chuyển đổi giữa các định dạng thời gian
Thư viện time.h
cung cấp nhiều hàm để chuyển đổi giữa các định dạng thời gian:
#include <iostream>
#include <ctime>
using namespace std;
int main() {
time_t now = time(0);
// 1. Từ time_t sang chuỗi
char* dt = ctime(&now);
cout << "ctime(): " << dt;
// 2. Từ time_t sang struct tm (giờ địa phương)
tm* local_time = localtime(&now);
cout << "Local time: " << asctime(local_time);
// 3. Từ time_t sang struct tm (giờ UTC)
tm* gmt_time = gmtime(&now);
cout << "UTC time: " << asctime(gmt_time);
// 4. Từ struct tm sang time_t
time_t time_again = mktime(local_time);
cout << "time_t value: " << time_again << " seconds since epoch" << endl;
return 0;
}
Định dạng thời gian tùy chỉnh
Hàm strftime()
cho phép định dạng thời gian theo ý muốn:
#include <iostream>
#include <ctime>
#include <cstring>
using namespace std;
int main() {
time_t now = time(0);
tm* ltm = localtime(&now);
char buffer[80];
// Định dạng: "Ngày DD/MM/YYYY HH:MM:SS"
strftime(buffer, sizeof(buffer), "Ngày %d/%m/%Y %H:%M:%S", ltm);
cout << buffer << endl;
// Định dạng khác: "Thứ W, ngày D tháng M năm Y"
setlocale(LC_ALL, "Vietnamese"); // Hỗ trợ tiếng Việt nếu có thể
strftime(buffer, sizeof(buffer), "Ngày %A, %d tháng %m năm %Y", ltm);
cout << buffer << endl;
return 0;
}
Tham khảo thêm: LRU Cache là gì? Cách hoạt động và triển khai chi tiết
Phương pháp 2: Sử dụng thư viện chrono hiện đại
Thư viện chrono
được giới thiệu từ C++11, mang đến cách tiếp cận hiện đại và mạnh mẽ hơn cho việc xử lý thời gian. Thư viện này được thiết kế với mục tiêu:
- Cung cấp độ chính xác cao hơn (đến nano giây)
- Hỗ trợ đa dạng đơn vị thời gian
- Tính toán thời gian an toàn hơn với kiểu dữ liệu mạnh
- Tương thích tốt hơn với lập trình đa luồng
Các thành phần chính của chrono
Thư viện chrono
bao gồm ba thành phần chính:
- Đồng hồ (Clocks): Cung cấp thông tin về thời điểm hiện tại.
- Khoảng thời gian (Duration): Biểu diễn khoảng thời gian giữa hai thời điểm.
- Thời điểm (Time point): Biểu diễn một thời điểm cụ thể.
Lấy thời gian hiện tại với chrono
#include <iostream>
#include <chrono>
#include <ctime>
using namespace std;
int main() {
// Lấy thời điểm hiện tại
auto now = chrono::system_clock::now();
// Chuyển đổi sang time_t để hiển thị dễ đọc
time_t current_time = chrono::system_clock::to_time_t(now);
// In thời gian hiện tại
cout << "Current date time: " << ctime(¤t_time);
return 0;
}
Đo thời gian thực thi với độ chính xác cao
Một trong những ưu điểm lớn của chrono
là khả năng đo thời gian với độ chính xác cao:
#include <iostream>
#include <chrono>
#include <thread>
#include <vector>
#include <algorithm>
using namespace std;
int main() {
vector<int> numbers(100000);
// Khởi tạo vector với các số ngẫu nhiên
for(int i = 0; i < numbers.size(); i++) {
numbers[i] = rand();
}
// Đo thời gian sắp xếp
auto start = chrono::high_resolution_clock::now();
// Đoạn code cần đo thời gian
sort(numbers.begin(), numbers.end());
// Kết thúc đo thời gian
auto end = chrono::high_resolution_clock::now();
// Tính thời gian thực thi với các đơn vị khác nhau
auto milliseconds = chrono::duration_cast<chrono::milliseconds>(end - start);
auto microseconds = chrono::duration_cast<chrono::microseconds>(end - start);
auto nanoseconds = chrono::duration_cast<chrono::nanoseconds>(end - start);
cout << "Sorting time:" << endl;
cout << milliseconds.count() << " mili seconds" << endl;
cout << microseconds.count() << " micro seconds" << endl;
cout << nanoseconds.count() << " nano seconds" << endl;
return 0;
}
Làm việc với các đơn vị thời gian khác nhau
chrono
cho phép làm việc với nhiều đơn vị thời gian khác nhau một cách dễ dàng:
#include <iostream>
#include <chrono>
using namespace std;
int main() {
// Tạo các khoảng thời gian
chrono::hours hrs(1); // 1 giờ
chrono::minutes mins(60); // 60 phút
chrono::seconds secs(60*60); // 3600 giây
chrono::milliseconds ms(60*60*1000); // 3,600,000 milli giây
// So sánh các khoảng thời gian
if (hrs == mins && mins == secs && secs == ms) {
cout << "All are equal!" << endl;
}
// Tạo khoảng thời gian phức tạp
auto complex_duration = hrs + chrono::minutes(30) + chrono::seconds(15);
// Chuyển đổi sang milli giây
auto ms_count = chrono::duration_cast<chrono::milliseconds>(complex_duration);
cout << "1 hour, 30 mins, 15 seconds = " << ms_count.count() << " milli seconds" << endl;
return 0;
}
Tính toán với thời điểm
#include <iostream>
#include <chrono>
#include <ctime>
#include <iomanip>
using namespace std;
int main() {
// Lấy thời điểm hiện tại
auto now = chrono::system_clock::now();
// Thêm 1 ngày vào thời điểm hiện tại
auto tomorrow = now + chrono::hours(24);
// Thêm 1 tuần
auto next_week = now + chrono::hours(24 * 7);
// Chuyển đổi sang time_t để hiển thị
time_t now_time = chrono::system_clock::to_time_t(now);
time_t tomorrow_time = chrono::system_clock::to_time_t(tomorrow);
time_t next_week_time = chrono::system_clock::to_time_t(next_week);
cout << "Current time: " << ctime(&now_time);
cout << "Tomorrow, same time: " << ctime(&tomorrow_time);
cout << "Next week, same time: " << ctime(&next_week_time);
// Tính khoảng thời gian giữa hai thời điểm
auto duration = next_week - now;
auto hours = chrono::duration_cast<chrono::hours>(duration);
cout << "From now until next week: " << hours.count() << " hours" << endl;
return 0;
}
Hiển thị đẹp hơn với C++20 (nếu có hỗ trợ)
Từ C++20, chrono
được mở rộng với nhiều tính năng mới, bao gồm kiểu calendar
và timezone
:
#include <iostream>
#include <chrono>
#include <format> // Yêu cầu C++20
using namespace std;
int main() {
// Lưu ý: Code này yêu cầu trình biên dịch hỗ trợ C++20
auto now = chrono::system_clock::now();
auto local_time = chrono::current_zone()->to_local(now);
// Sử dụng std::format cho định dạng thời gian đẹp
cout << format("Date: {:%d/%m/%Y}", local_time) << endl;
cout << format("Time: {:%H:%M:%S}", local_time) << endl;
cout << format("Full: {:%A, %d %B %Y at %H:%M:%S}", local_time) << endl;
return 0;
}
So sánh các phương pháp
Dưới đây là bảng so sánh chi tiết giữa hai phương pháp chính:
Tiêu chí | time.h | chrono |
---|---|---|
Độ chính xác | Giây | Nano giây |
Dễ sử dụng cho người mới | ✓✓✓ | ✓✓ |
Tính năng | Cơ bản | Nâng cao |
Hiệu suất | Tốt | Rất tốt |
Tương thích | C++98 trở lên | C++11 trở lên |
An toàn kiểu | Thấp | Cao |
Hỗ trợ timezone | Hạn chế | Tốt (từ C++20) |
Tương thích đa luồng | Hạn chế | Tốt |
Tính toán thời gian | Thủ công | Tích hợp |
Mức độ phổ biến trong code cũ | Rất cao | Thấp |
Mức độ phổ biến trong code mới | Trung bình | Cao |
Khi nào nên sử dụng time.h?
- Khi bạn mới học C++ và cần một giải pháp đơn giản
- Khi làm việc với các dự án cũ hoặc cần tương thích với C
- Khi chỉ cần độ chính xác đến giây là đủ
- Khi cần hiển thị thời gian dưới dạng chuỗi nhanh chóng
Khi nào nên sử dụng chrono?
- Khi bạn cần độ chính xác cao (milli, micro, nano giây)
- Khi làm việc với các tính toán thời gian phức tạp
- Khi phát triển ứng dụng đa luồng
- Khi cần tương thích với các API hiện đại
- Khi bạn muốn code an toàn và dễ bảo trì hơn
Các định dạng hiển thị thời gian phổ biến
Khi hiển thị thời gian, việc chọn định dạng phù hợp là rất quan trọng. Dưới đây là một số định dạng phổ biến và cách triển khai:
Với time.h và strftime()
#include <iostream>
#include <ctime>
using namespace std;
int main() {
time_t now = time(0);
tm* ltm = localtime(&now);
char buffer[80];
// Bảng các định dạng phổ biến
cout << "Common date formats:" << endl;
// 1. DD/MM/YYYY
strftime(buffer, 80, "%d/%m/%Y", ltm);
cout << "1. " << buffer << endl;
// 2. MM/DD/YYYY (US format)
strftime(buffer, 80, "%m/%d/%Y", ltm);
cout << "2. " << buffer << endl;
// 3. YYYY-MM-DD (ISO format)
strftime(buffer, 80, "%Y-%m-%d", ltm);
cout << "3. " << buffer << endl;
// 4. DD Month YYYY (Ex: 01 January 2023)
strftime(buffer, 80, "%d %B %Y", ltm);
cout << "4. " << buffer << endl;
// 5. Weekday, Day Month Year
strftime(buffer, 80, "%A, %d %B %Y", ltm);
cout << "5. " << buffer << endl;
cout << "\nCommon time formats:" << endl;
// 1. HH:MM:SS
strftime(buffer, 80, "%H:%M:%S", ltm);
cout << "1. " << buffer << endl;
// 2. HH:MM:SS AM/PM
strftime(buffer, 80, "%I:%M:%S %p", ltm);
cout << "2. " << buffer << endl;
// 3. 24-hour time with timezone
strftime(buffer, 80, "%H:%M:%S %Z", ltm);
cout << "3. " << buffer << endl;
return 0;
}
Với C++20 (format)
Nếu bạn đang sử dụng C++20, bạn có thể sử dụng thư viện format
để định dạng thời gian một cách dễ dàng hơn:
#include <iostream>
#include <chrono>
#include <format>
using namespace std;
int main() {
auto now = chrono::system_clock::now();
auto today = chrono::year_month_day{chrono::floor<chrono::days>(now)};
// Date formats
cout << format("DD/MM/YYYY: {:%d/%m/%Y}", now) << endl;
cout << format("YYYY-MM-DD: {:%Y-%m-%d}", now) << endl;
cout << format("Full date: {:%A, %d %B %Y}", now) << endl;
// Time formats
cout << format("Time: {:%H:%M:%S}", now) << endl;
cout << format("Time with AM/PM: {:%I:%M:%S %p}", now) << endl;
cout << format("Full date and time: {:%d/%m/%Y %H:%M:%S}", now) << endl;
return 0;
}
Ứng dụng thực tế
1. Đo thời gian thực thi chương trình
#include <iostream>
#include <chrono>
#include <vector>
#include <algorithm>
using namespace std;
// Hàm sắp xếp nổi bọt
void bubbleSort(vector<int>& arr) {
int n = arr.size();
for (int i = 0; i < n-1; i++)
for (int j = 0; j < n-i-1; j++)
if (arr[j] > arr[j+1])
swap(arr[j], arr[j+1]);
}
int main() {
// Tạo mảng ngẫu nhiên
const int SIZE = 10000;
vector<int> arr1(SIZE), arr2(SIZE);
for (int i = 0; i < SIZE; i++) {
int num = rand() % 10000;
arr1[i] = arr2[i] = num;
}
// Đo thời gian sắp xếp nổi bọt
auto start1 = chrono::high_resolution_clock::now();
bubbleSort(arr1);
auto end1 = chrono::high_resolution_clock::now();
auto duration1 = chrono::duration_cast<chrono::milliseconds>(end1 - start1);
// Đo thời gian sắp xếp của thư viện chuẩn
auto start2 = chrono::high_resolution_clock::now();
sort(arr2.begin(), arr2.end());
auto end2 = chrono::high_resolution_clock::now();
auto duration2 = chrono::duration_cast<chrono::milliseconds>(end2 - start2);
cout << "Bubble sort running time: " << duration1.count() << " ms" << endl;
cout << "std::sort running time: " << duration2.count() << " ms" << endl;
cout << "std::sort faster than " << (float)duration1.count() / duration2.count() << " times" << endl;
return 0;
}
2. Tạo một đồng hồ đếm ngược
#include <iostream>
#include <chrono>
#include <thread>
#include <conio.h> // Cho getch() - Lưu ý: chỉ hoạt động trên Windows
using namespace std;
int main() {
int minutes = 0, seconds = 0;
cout << "Enter minutes: ";
cin >> minutes;
cout << "Enter seconds: ";
cin >> seconds;
int total_seconds = minutes * 60 + seconds;
cout << "Countdown started! Press any key to stop.\n";
for (int i = total_seconds; i >= 0; i--) {
// Xóa màn hình theo cách đơn giản (không hiệu quả lắm)
system("cls"); // Windows
// system("clear"); // Linux/Mac
int m = i / 60;
int s = i % 60;
cout << "Time remaining: ";
cout << (m < 10 ? "0" : "") << m << ":";
cout << (s < 10 ? "0" : "") << s << endl;
// Kiểm tra nếu người dùng nhấn phím
if (_kbhit()) {
_getch(); // Đọc phím đã nhấn
cout << "Timer stopped!" << endl;
break;
}
// Đợi 1 giây
this_thread::sleep_for(chrono::seconds(1));
}
cout << "Countdown finished!" << endl;
return 0;
}
Câu hỏi thường gặp (FAQs)
1. Làm sao để xử lý múi giờ khác nhau?
Để xử lý múi giờ, bạn có thể:
- Với
time.h
: Sử dụnggmtime()
cho UTC vàlocaltime()
cho giờ địa phương - Với
chrono
(C++20): Sử dụngchrono::zoned_time
vàchrono::current_zone()
#include <iostream>
#include <ctime>
using namespace std;
int main() {
time_t now = time(0);
// Giờ địa phương
tm* local = localtime(&now);
cout << "Local time: " << asctime(local);
// Giờ UTC
tm* utc = gmtime(&now);
cout << "UTC time: " << asctime(utc);
return 0;
}
2. Làm thế nào để tính khoảng cách giữa hai thời điểm?
- Với
time.h
: Lấy hiệu của hai giá trịtime_t
- Với
chrono
: Sử dụng phép trừ vàduration_cast
time_t t1 = time(0);
// ... một số xử lý
time_t t2 = time(0);
double seconds = difftime(t2, t1);
3. Tại sao không nên sử dụng ctime()
trong code sản phẩm?
ctime()
có một số hạn chế:
- Không thread-safe
- Định dạng cố định, không thể tùy chỉnh
- Trả về chuỗi kết thúc bằng newline
- Buffer có thể bị ghi đè trong các lời gọi tiếp theo
Thay vào đó, nên sử dụng:
strftime()
vớitime.h
format
(C++20) hoặc thư viện định dạng thời gian khác
4. Làm sao để xử lý lỗi “Year 2038 problem”?
Vấn đề năm 2038 xảy ra vì time_t
thường là số nguyên 32-bit có dấu. Giải pháp:
- Sử dụng hệ thống 64-bit (time_t sẽ là 64-bit)
- Dùng
chrono
thay vìtime.h
- Sử dụng kiểu dữ liệu thời gian tùy chỉnh cho ứng dụng
5. Có cách nào để đo thời gian chính xác đến micro/nano giây?
- KHÔNG sử dụng
time()
vì chỉ chính xác đến giây - Sử dụng
chrono::high_resolution_clock
:
auto start = chrono::high_resolution_clock::now();
// ... code cần đo
auto end = chrono::high_resolution_clock::now();
auto duration = chrono::duration_cast<chrono::microseconds>(end - start);
cout << duration.count() << " microseconds" << endl;
6. Làm sao để xử lý thời gian trong đa luồng (multithreading)?
- Tránh sử dụng các hàm không thread-safe như
localtime()
- Thay vào đó, sử dụng:
localtime_r()
(phiên bản thread-safe củalocaltime
)- Thư viện
chrono
(thread-safe by design) - Mutex khi truy cập shared time resources
Kết luận
Việc lấy và xử lý thời gian trong C++ có thể thực hiện thông qua hai phương pháp chính:
- Sử dụng
time.h
cho các ứng dụng đơn giản và yêu cầu tương thích ngược - Sử dụng
chrono
cho các ứng dụng hiện đại cần độ chính xác cao và tính năng phong phú
Tùy vào yêu cầu cụ thể của dự án, bạn có thể chọn phương pháp phù hợp. Với người mới bắt đầu, nên làm quen với time.h
trước, sau đó từng bước chuyển sang sử dụng chrono
khi cần các tính năng nâng cao hơn.
Hy vọng bài viết này đã giúp bạn hiểu rõ hơn về cách lấy thời gian hiện tại trong C++. Hãy thực hành các ví dụ trên và khám phá thêm các tính năng khác của hai thư viện này nhé!