2734b36a566e5a9fe63cd9ff0d1246405116abca
[notmuch] / notmuch-time.c
1 /* notmuch - Not much of an email program, (just index and search)
2  *
3  * Copyright © 2009 Carl Worth
4  *
5  * This program is free software: you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation, either version 3 of the License, or
8  * (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program.  If not, see https://www.gnu.org/licenses/ .
17  *
18  * Author: Carl Worth <cworth@cworth.org>
19  */
20
21 #include "notmuch-client.h"
22
23 /* Format a nice representation of 'time' relative to the current time.
24  *
25  * Examples include:
26  *
27  *      5 mins. ago     (For times less than 60 minutes ago)
28  *      Today 12:30     (For times >60 minutes but still today)
29  *      Yest. 12:30
30  *      Mon.  12:30     (Before yesterday but fewer than 7 days ago)
31  *      October 12      (Between 7 and 180 days ago (about 6 months))
32  *      2008-06-30      (More than 180 days ago)
33  *
34  * The returned string is either static data (a string literal) or
35  * newly talloced data belonging to 'ctx'. That is, the caller should
36  * not modify nor free the returned value. But when the caller
37  * arranges for 'ctx' to be talloc_freed, then memory allocated here
38  * (if any) will be reclaimed.
39  *
40  */
41 #define MINUTE (60)
42 #define HOUR (60 * MINUTE)
43 #define DAY (24 * HOUR)
44 #define RELATIVE_DATE_MAX 20
45 const char *
46 notmuch_time_relative_date (const void *ctx, time_t then)
47 {
48     struct tm tm_now, tm_then;
49     time_t now = time(NULL);
50     time_t delta;
51     char *result;
52
53     localtime_r (&now, &tm_now);
54     localtime_r (&then, &tm_then);
55
56     result = talloc_zero_size (ctx, RELATIVE_DATE_MAX);
57     if (result == NULL)
58         return "when?";
59
60     if (then > now)
61         return "the future";
62
63     delta = now - then;
64
65     if (delta > 180 * DAY) {
66         strftime (result, RELATIVE_DATE_MAX,
67                   "%F", &tm_then); /* 2008-06-30 */
68         return result;
69     }
70
71     if (delta < 3600) {
72         snprintf (result, RELATIVE_DATE_MAX,
73                   "%d mins. ago", (int) (delta / 60));
74         return result;
75     }
76
77     if (delta <= 7 * DAY) {
78         if (tm_then.tm_wday == tm_now.tm_wday &&
79             delta < DAY)
80         {
81             strftime (result, RELATIVE_DATE_MAX,
82                       "Today %R", &tm_then); /* Today 12:30 */
83             return result;
84         } else if ((tm_now.tm_wday + 7 - tm_then.tm_wday) % 7 == 1) {
85             strftime (result, RELATIVE_DATE_MAX,
86                       "Yest. %R", &tm_then); /* Yest. 12:30 */
87             return result;
88         } else {
89             if (tm_then.tm_wday != tm_now.tm_wday) {
90                 strftime (result, RELATIVE_DATE_MAX,
91                           "%a. %R", &tm_then); /* Mon. 12:30 */
92                 return result;
93             }
94         }
95     }
96
97     strftime (result, RELATIVE_DATE_MAX,
98               "%B %d", &tm_then); /* October 12 */
99     return result;
100 }
101 #undef MINUTE
102 #undef HOUR
103 #undef DAY
104
105 void
106 notmuch_time_print_formatted_seconds (double seconds)
107 {
108     int hours;
109     int minutes;
110
111     if (seconds < 1) {
112         printf ("almost no time");
113         return;
114     }
115
116     if (seconds > 3600) {
117         hours = (int) seconds / 3600;
118         printf ("%dh ", hours);
119         seconds -= hours * 3600;
120     }
121
122     if (seconds > 60) {
123         minutes = (int) seconds / 60;
124         printf ("%dm ", minutes);
125         seconds -= minutes * 60;
126     }
127
128     printf ("%ds", (int) seconds);
129 }
130
131 /* Compute the number of seconds elapsed from start to end. */
132 double
133 notmuch_time_elapsed (struct timeval start, struct timeval end)
134 {
135     return ((end.tv_sec - start.tv_sec) +
136             (end.tv_usec - start.tv_usec) / 1e6);
137 }