I am implementing a version of ls -la
command in OS X. I happened to notice that ls
command lists years for some files and times for others as shown below:
-rwxr-xr-x 1 Jenna 197609 3584 Mar 13 2015 untitled1.exe*
drwxr-xr-x 1 Jenna 197609 0 Mar 2 07:48 Videos/
After some research, I found out that files older than 6 months gets a year while those that are not get the actual time. How do I get the date and times of these files to correctly display either the year or time ? Currently I have the following code which always displays the time:
int main()
{
struct stat *fileInfo;
char dir[] = "~/Desktop/file.txt";
stat(dir, &fileInfo);
printf("%.12s ", 4+ctime(&fileInfo->st_mtimespec));
return 0;
}
strftime
is your friend here. Formatting it like ls
is not that straight forward. The two formats that ls in coreutils is using are
"%b %e %Y"
"%b %e %H:%M"
Heres one paragraph from the docs of the ls in coreutils
/* TRANSLATORS: ls output needs to be aligned for ease of reading, so be wary of using variable width fields from the locale. Note %b is handled specially by ls and aligned correctly. Note also that specifying a width as in %5b is erroneous as strftime will count bytes rather than characters in multibyte locales. */ N_("%b %e %H:%M")
They're taking into consideration things like Locale ie multibyte characters etc. They also discuss things like when a file is older than N months they change how it's displayed etc. You can find a lot of information here...
http://git.savannah.gnu.org/cgit/coreutils.git/tree/src/ls.c
For your needs something simpler might be fine, heres some code that might point you in the correct direction. You can change the format to whatever you want by changing the third argument to strftime
.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
int main(void) {
time_t t;
srand((unsigned) time(&t));
size_t i = 0;
struct timespec ttime;
while(i < 0xffffffff) {\
ttime.tv_sec = i;
i += 3600;
struct tm time_struct;
localtime_r(&ttime.tv_sec, &time_struct);
char time_str[1024];
if(rand() > RAND_MAX/2) {
strftime(time_str, sizeof(time_str), "a == %b %e %Y", &time_struct);
}
else {
strftime(time_str, sizeof(time_str), "b == %b %e %H:%M", &time_struct);
}
printf("%s\n", time_str);
}
exit(0);
}
Try it and see what it does. From the man page, tweaking it will get you really close to what you need.
size_t strftime(char *restrict s, size_t maxsize, const char *restrict format, const struct tm *restrict timeptr);
The strftime() function formats the information from timeptr into the buffer s, according to the string pointed to by format.
If I recall correctly, the determining factor used by ls -l
to output a date/time
or output a date/year
is whether the mtime
year returned by stat
matches the current year. If the file mtime
year matches the current
year, then date/time
information is provided, if the mtime
year is not the current year, then date/year
information is provided.
In order to make the comparison, you need to fill a struct tm
for both the file mtime
and now
. The following example uses localtime_r
to fill each struct tm
, makes the comparison, and then outputs the file details accordingly.
(the code will read/compare mtimes
s and output the time format for all filenames provided as arguments. (a placeholder string is used to provide basic formatting for the file permissions, number, user, group, size, etc.)
#include <stdio.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <time.h>
#define MAXC 64
void dump_tm (struct tm *t);
int main(int argc, char **argv)
{
int i = 0;
char time_str[MAXC] = "";
time_t now = time (NULL);
struct stat sb;
struct tm tmfile, tmnow;
if (argc < 2) { /* validate sufficient arguments provided */
fprintf (stderr, "error: insufficient input, usage: %s <pathname>\n",
argv[0]);
return 1;
}
for (i = 1; i < argc; i++) { /* for each file given as arg */
if (stat(argv[i], &sb) == -1) { /* validate stat of file */
perror("stat");
return 1;
}
localtime_r (&sb.st_mtime, &tmfile); /* get struct tm for file */
localtime_r (&now, &tmnow); /* and now */
if (tmfile.tm_year == tmnow.tm_year) { /* compare year values */
strftime (time_str, sizeof (time_str), "%b %e %H:%M",
&tmfile); /* if year is current output date/time */
printf ("permission 1 user group 12345 %s %s\n",
time_str, argv[i]);
}
else { /* if year is not current, output time/year */
strftime (time_str, sizeof (time_str), "%b %e %Y",
&tmfile);
printf ("permission 1 user group 12345 %s %s\n",
time_str, argv[i]);
}
}
return 0;
}
Example ls -l
Output
$ ls -l tmp.c ls_time_date_fmt.c
-rw-r--r-- 1 david david 1312 Apr 6 03:15 ls_time_date_fmt.c
-rw-r--r-- 1 david david 2615 May 23 2014 tmp.c
Program Use/Output
$ ./bin/ls_time_date_fmt ls_time_date_fmt.c tmp.c
permission 1 user group 12345 Apr 6 03:15 ls_time_date_fmt.c
permission 1 user group 12345 May 23 2014 tmp.c
Let me know if you have any questions.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.