我目前正在C中创建个人日记,我希望能够打印按日期排序的帖子。我可以使用struct tm提取日期,但我不知道如何对日期进行排序,以便最新的日期排在最前面。 这是我的全部功能:
void dateOrder() {
FILE *postfile = fopen("post.txt", "r");
int numofpost = getNumOfPost(postfile);
int dates[numofpost];
struct tm ptime;
char *elt = malloc(5 * sizeof(char));
char *dref = "Date";
char *href = "Heure";
char c = 'c';
char *pseudo = malloc(20 * sizeof(char));
int pseudolen = 0;
rewind(postfile);
while (!feof(postfile)) {
fscanf(postfile, "%s", elt);
if (strcmp(elt, dref) == 0) {
fseek(postfile, 3, SEEK_CUR);
fscanf(postfile, "%d/%d/%d", (int)&(ptime.tm_mday), (int)&(ptime.tm_mon), (int)&(ptime.tm_year));
}
if (strcmp(elt, href) == 0) {
fseek(postfile, 3, SEEK_CUR);
fscanf(postfile, "%d:%d", (int)&(ptime.tm_hour), (int)&(ptime.tm_min));
}
ptime.tm_year -= 1900;
ptime.tm_mon -= 1;
ptime.tm_sec = 0;
ptime.tm_isdst = -1;
int rep = mktime(&ptime);
if (rep != -1) {
dates[i++] = rep;
}
}
insertsort(dates, sizeof(dates)/sizeof(dates[0]));
for (int i = 0; i < numofpost; i++) {
c = 'c';
rewind(postfile);
while (!feof(postfile) && c != 24) {
fscanf(postfile, "%s", elt);
if (strcmp(elt, "Pseudo") == 0) {
fseek(postfile, 3, SEEK_CUR);
fscanf(postfile, "%s", pseudo);
pseudolen = strlen(pseudo);
}
if (strcmp(elt, dref) == 0) {
fseek(postfile, 3, SEEK_CUR);
fscanf(postfile, "%d/%d/%d", (int)&(ptime.tm_mday), (int)&(ptime.tm_mon), (int)&(ptime.tm_year));
}
if (strcmp(elt, href) == 0) {
fseek(postfile, 3, SEEK_CUR);
fscanf(postfile, "%d:%d", (int)&(ptime.tm_hour), (int)&(ptime.tm_min));
}
ptime.tm_year -= 1900;
ptime.tm_mon -= 1;
ptime.tm_sec = 0;
ptime.tm_isdst = -1;
int mkt = mktime(&ptime);
if (mkt == dates[i]) {
fseek(postfile, -39, SEEK_CUR);
fseek(postfile, -pseudolen, SEEK_CUR);
while (c != 24) {
c = fgetc(postfile);
if (c == 24)
continue;
printf("%c", c);
}
}
}
}
fclose(postfile);
}
这是struct tm:
struct tm {
int tm_sec; /* seconds, range 0 to 59 */
int tm_min; /* minutes, range 0 to 59 */
int tm_hour; /* hours, range 0 to 23 */
int tm_mday; /* day of the month, range 1 to 31 */
int tm_mon; /* month, range 0 to 11 */
int tm_year; /* The number of years since 1900 */
int tm_wday; /* day of the week, range 0 to 6 */
int tm_yday; /* day in the year, range 0 to 365 */
int tm_isdst; /* daylight saving time */
};
答案 0 :(得分:3)
您可以使用mktime()
和difftime()
编写比较函数,然后使用qsort()
对tm
结构数组进行排序。 cmp_dates_descend()
可以使用下面的比较函数qsort()
按降序对日期数组进行排序:
#include <stdlib.h>
#include <time.h>
#define NUM_DATES 10 /* for example */
int cmp_dates_descend(const void *d1, const void *d2);
int main(void)
{
/* ... */
struct tm arr_dates[NUM_DATES];
/* ... */
size_t num_dates = sizeof arr_dates / sizeof *arr_dates;
qsort(arr_dates, num_dates, sizeof *arr_dates, cmp_dates_descend);
/* ... */
return 0;
}
int cmp_dates_descend(const void *d1, const void *d2)
{
struct tm *date_1 = (struct tm *) d1;
struct tm *date_2 = (struct tm *) d2;
return double d = -difftime(mktime(date_1), mktime(date_2));
}
请注意,此方法可能会遇到大日期差异的问题。由于difftime()
返回double
(表示以秒为单位的时间差),因此返回值可能无法在int
中表示,qsort()
是{{1}使用的比较函数返回的值}}。 INT_MAX == 2147483647
,典型的4字节int
,大于68年的日期差异会导致从double
到int
的转换溢出,从而导致未定义的行为。如果要处理这样大的日期差异,可能应该编写自定义排序函数。
修改强>
@chqrlie在评论中指出,这种方法也可能导致对非常接近的日期(几分之一秒)进行错误的比较,因为如果difftime(mktime(date_1), mktime(date_2))
的数量小于1
,值将在返回时转换为0
,因此比较为相等。为避免此复杂情况,difftime()
的结果可以存储在double
中,并与0
进行比较以确定返回值。这是比较函数的常见技巧;这也消除了以前的大日期差异问题。这是一个改进的比较函数:
int cmp_dates_descend(const void *d1, const void *d2)
{
struct tm *date_1 = (struct tm *) d1;
struct tm *date_2 = (struct tm *) d2;
double d = difftime(mktime(date_1), mktime(date_2));
return (d < 0) - (d > 0);
}
修改2
为了保持数组不变,比较函数应该在获取const
指向数组元素的指针时执行,我们可以在比较函数中复制tm
结构并调用{ {1}}以较低的性能成本复制副本:
mktime()
答案 1 :(得分:0)
感谢这里的答案和评论是我如何打印按日期排序的帖子
int check(int i, struct tm *dates, struct tm ptime){
if(dates[i].tm_year == ptime.tm_year && dates[i].tm_mon == ptime.tm_mon &&
dates[i].tm_mday == ptime.tm_mday && dates[i].tm_hour == ptime.tm_hour &&
dates[i].tm_min == ptime.tm_min)
return 1;
return 0;
}
int compareDates(const void *d1, const void *d2){
struct tm date_1 = *(const struct tm *)d1;
struct tm date_2 = *(const struct tm *)d2;
double d = difftime(mktime(&date_1), mktime(&date_2));
return (d < 0) - (d > 0);
}
void dateOrder(){ //print the post sorted by date
FILE *postfile = fopen("post.txt", "r");
int numofpost = getNumOfPost(postfile);
struct tm dates[numofpost];
int pseudolen = 0, i = 0;
struct tm ptime;
char *elt = malloc(5*sizeof(char));
char *pseudo = malloc(20*sizeof(char));
char *dref = "Date"; //Word to find to get the date
char *href = "Heure"; //Word to find to get hour
char c = 'c';
rewind(postfile);
while(!feof(postfile)){
fscanf(postfile, "%s", elt);
if(strcmp(elt, dref) == 0){
fseek(postfile, 3, SEEK_CUR);
fscanf(postfile, "%d/%d/%d", (int)&(ptime.tm_mday), (int)&(ptime.tm_mon), (int)&(ptime.tm_year));
dates[i].tm_year = ptime.tm_year;
dates[i].tm_mon = ptime.tm_mon;
dates[i].tm_mday = ptime.tm_mday;
}
if(strcmp(elt, href) == 0){
fseek(postfile, 3, SEEK_CUR);
fscanf(postfile, "%d:%d", (int)&(ptime.tm_hour), (int)&(ptime.tm_min));
dates[i].tm_hour = ptime.tm_hour;
dates[i++].tm_min = ptime.tm_min;
}
}
size_t num_dates = sizeof(dates)/sizeof(*dates);
qsort(dates, num_dates, sizeof(*dates), compareDates);
for(int i = 0; i < numofpost; i++){
c = 'c';
rewind(postfile);
while(!feof(postfile) && c != 24){ //We read the file until the end c is equal to 24 only if a already founded the wanted post
fscanf(postfile, "%s", elt);
if(strcmp(elt, "Pseudo") == 0){
fseek(postfile, 3, SEEK_CUR);
fscanf(postfile, "%s", pseudo);
pseudolen = strlen(pseudo);
}
if(strcmp(elt, dref) == 0){
fseek(postfile, 3, SEEK_CUR);
fscanf(postfile, "%d/%d/%d", (time_t)&(ptime.tm_mday), (time_t)&(ptime.tm_mon), (time_t)&(ptime.tm_year));
}
if(strcmp(elt, href) == 0){
fseek(postfile, 3, SEEK_CUR);
fscanf(postfile, "%d:%d", (time_t)&(ptime.tm_hour), (time_t)&(ptime.tm_min));
}
if(check(i, dates, ptime)){ //check look if the member of struct are the same in dates ans ptime
fseek(postfile, -40, SEEK_CUR);
fseek(postfile, -pseudolen, SEEK_CUR);
while(c != 24){ //while c != 24 is because user has stop typing a post when typing Ctrl + X == 24 in ascii code
c = fgetc(postfile);
if(c == 24)
continue;
printf("%c", c);
}
}
if(ftell(postfile)+15 < feof(postfile)) //If it is not the last post
fseek(postfile, 15, SEEK_CUR); //I go to next post*
}
printf("\n\n\n\n");
}
fclose(postfile);
printf("\n\n");
}