C
Completed
-
Section 1: Getting Started
-
Section 2: Core Syntax
-
Section 3: Functions
-
Section 4: Arrays and Strings
-
Section 5: Pointers
-
Section 6: Memory Management
-
Section 7: Structures and Unions
-
Section 8: The Preprocessor and Build Process
-
Section 9: Standard Library: stdio.h
-
Section 10: Standard Library: stdlib.h
-
Section 11: Standard Library: string.h
-
Section 12: Standard Library: ctype.h and wctype.h
-
Section 13: Standard Library: math.h, complex.h, fenv.h, tgmath.h
-
Section 14: Standard Library: Type and Limit Headers
-
Section 15: Standard Library: Error Handling and Debugging
-
Section 16: Standard Library: Localization and Encoding
-
Section 17: Standard Library: time.h
-
Section 18: Standard Library: Concurrency (C11)
-
Section 19: POSIX and System Programming (unistd.h)
-
Section 20: More Data Structures
-
Section 21: Algorithms in C
-
Section 22: Bitwise Operations
-
Section 23: Command-Line Programs
-
Section 24: Debugging and Best Practices
-
Section 25: Compiler and Language Internals
-
Section 26: Embedded and Cross-Platform Considerations
-
Section 27: Networking Basics
-
Section 28: Practical Projects
-
Section 29: Interview Practice
-
Section 30: C23 Modern Features
-
Section 31: More Practice and Review
132: Formatting Time with strftime
I remember a junior dev on my team a few years back who spent an entire afternoon scratching his head because his log timestamps were coming up empty. He had the logic right, he was calling the functions in the right order, but the output was just... nothing. Here is a snippet of the code he showed me:
#include <stdio.h>
#include <time.h>
int main() {
time_t rawtime = time(NULL);
struct tm *timeinfo = localtime(&rawtime);
char buffer[10];
// He wanted "2023-10-25 14:30:05"
strftime(buffer, 10, "%Y-%m-%d %H:%M:%S", timeinfo);
printf("Current time: %s\n", buffer);
return 0;
}
The Silent Failure of Small Buffers
The problem here is subtle because the code doesn't crash. It doesn't segfault, and it doesn't throw a warning. It just fails silently. He allocated 10 bytes for buffer, but the format string "%Y-%m-%d %H:%M:%S" requires about 20 characters (including the null terminator).
In C, strftime is actually safer than sprintf because it takes the maximum size of the buffer as an argument. However, if the resulting string—including the null terminator—exceeds that size, strftime doesn't just truncate the string; it returns 0 and leaves the contents of the buffer in an undefined state (usually empty or partially filled). Because he wasn't checking the return value, he had no idea the function was failing.
Giving the String Room to Breathe
The first thing we did was give the buffer a reasonable size. Unless you are working in an extremely memory-constrained embedded system, there's no reason to be stingy with a few bytes for a timestamp. A buffer of 64 or 128 is usually plenty. I also taught him to check the return value. If strftime returns 0, it means your buffer was too small.
#include <stdio.h>
#include <time.h>
int main() {
time_t rawtime = time(NULL);
struct tm *timeinfo = localtime(&rawtime);
char buffer[64]; // Plenty of space now
if (strftime(buffer, sizeof(buffer), "%Y-%m-%d %H:%M:%S", timeinfo) == 0) {
fprintf(stderr, "Buffer too small for the requested format\n");
return 1;
}
printf("Current time: %s\n", buffer);
return 0;
}
Picking the Right Specifiers
Once we got the string to actually appear, we realized he was mixing up his case. In strftime, case matters immensely. It's not like printf where %d is always an integer. Here, %Y (uppercase) gives you the full year (2023), while %y (lowercase) gives you the two-digit year (23).
I usually keep a cheat sheet for these, but here are the ones you'll actually use 90% of the time:
%Y: Year with century (e.g., 2023)%m: Month as a decimal number (01-12)%d: Day of the month (01-31)%H: Hour in 24h format (00-23)%M: Minute (00-59)%S: Second (00-59)%A: Full weekday name (e.g., Wednesday)%B: Full month name (e.g., October)
One thing to watch out for: strftime is locale-dependent. If your program runs on a machine set to a French locale, %A will output "mercredi" instead of "Wednesday". If you need a consistent format regardless of where the code is running, stick to the numeric specifiers like %Y-%m-%d.
📋 Practical Task
Build a Custom Audit Log Timestamp Generator
Write a C program that mimics a professional audit log entry. Your program should:
- Get the current system time.
- Use
strftimeto format the time into a string that looks exactly like this:[Wednesday, October 25, 2023 | 14:30:05]. - Ensure you use a buffer large enough to hold this long string and include a check to verify that
strftimesucceeded. - Print the resulting timestamp followed by a dummy log message, like:
[Wednesday, October 25, 2023 | 14:30:05] USER_LOGIN: User 'admin' logged in from 192.168.1.1.
There are no comments for now.