]> git.ipfire.org Git - thirdparty/dovecot/core.git/commitdiff
lib: Add time_to_local_day_start()
authorTimo Sirainen <timo.sirainen@dovecot.fi>
Tue, 28 Mar 2017 16:14:00 +0000 (19:14 +0300)
committerTimo Sirainen <timo.sirainen@dovecot.fi>
Thu, 30 Mar 2017 18:06:35 +0000 (21:06 +0300)
src/lib/test-time-util.c
src/lib/time-util.c
src/lib/time-util.h

index bd4fdf17e51c0a35b55f63c27889ed1f75f0dccb..ac500946fc612d1e8375b760ed418a9cd6d315e6 100644 (file)
@@ -70,6 +70,59 @@ static void test_timeval_diff(void)
        test_end();
 }
 
+static void test_time_to_local_day_start(void)
+{
+       /* Try this around days when DST changes in some of the more popular
+          timezones. If that works, everything else probably works too. */
+       const struct tm tests[] = {
+               /* Europe winter -> summer */
+               { .tm_year = 2017-1900, .tm_mon = 2, .tm_mday = 26 },
+               { .tm_year = 2017-1900, .tm_mon = 2, .tm_mday = 26,
+                 .tm_hour = 23, .tm_min = 59, .tm_sec = 59 },
+               /* Europe summer -> winter */
+               { .tm_year = 2017-1900, .tm_mon = 9, .tm_mday = 29 },
+               { .tm_year = 2017-1900, .tm_mon = 9, .tm_mday = 29,
+                 .tm_hour = 23, .tm_min = 59, .tm_sec = 59 },
+               /* USA winter -> summer */
+               { .tm_year = 2017-1900, .tm_mon = 2, .tm_mday = 12 },
+               { .tm_year = 2017-1900, .tm_mon = 2, .tm_mday = 12,
+                 .tm_hour = 23, .tm_min = 59, .tm_sec = 59 },
+               /* USA summer -> winter */
+               { .tm_year = 2017-1900, .tm_mon = 10, .tm_mday = 5 },
+               { .tm_year = 2017-1900, .tm_mon = 10, .tm_mday = 5,
+                 .tm_hour = 23, .tm_min = 59, .tm_sec = 59 },
+
+               /* (some of) Australia summer -> winter */
+               { .tm_year = 2017-1900, .tm_mon = 3, .tm_mday = 2 },
+               { .tm_year = 2017-1900, .tm_mon = 3, .tm_mday = 2,
+                 .tm_hour = 23, .tm_min = 59, .tm_sec = 59 },
+               /* (some of) Australia winter -> summer */
+               { .tm_year = 2017-1900, .tm_mon = 9, .tm_mday = 1 },
+               { .tm_year = 2017-1900, .tm_mon = 9, .tm_mday = 1,
+                 .tm_hour = 23, .tm_min = 59, .tm_sec = 59 },
+       };
+       const struct tm *tm;
+       struct tm tm_copy;
+       time_t t;
+
+       test_begin("time_to_local_day_start()");
+       for (unsigned i = 0; i < N_ELEMENTS(tests); i++) {
+               tm_copy = tests[i];
+               tm_copy.tm_isdst = -1;
+               t = mktime(&tm_copy);
+               test_assert_idx(t != (time_t)-1, i);
+
+               t = time_to_local_day_start(t);
+               tm = localtime(&t);
+               test_assert_idx(tm->tm_year == tests[i].tm_year &&
+                               tm->tm_mon == tests[i].tm_mon &&
+                               tm->tm_mday == tests[i].tm_mday, i);
+               test_assert_idx(tm->tm_hour == 0 && tm->tm_min == 0 &&
+                               tm->tm_sec == 0, i);
+       }
+       test_end();
+}
+
 static void test_timestamp(const char *ts, int idx)
 {
        /* %G:%H:%M:%S */
@@ -130,6 +183,7 @@ void test_time_util(void)
 {
        test_timeval_cmp();
        test_timeval_diff();
+       test_time_to_local_day_start();
        test_strftime_now();
        test_strftime_fixed();
 }
index 695cc5e4ec9119b7162be6866703eb3c5751722a..a783de988a03f5190ca4728b40b7033ac2b068ec 100644 (file)
@@ -55,6 +55,23 @@ long long timeval_diff_usecs(const struct timeval *tv1,
        return ((long long)secs * 1000000LL) + usecs;
 }
 
+time_t time_to_local_day_start(time_t t)
+{
+       const struct tm *day_tm;
+       struct tm tm;
+       time_t new_start_time;
+
+       day_tm = localtime(&t);
+       i_zero(&tm);
+       tm.tm_year = day_tm->tm_year;
+       tm.tm_mon = day_tm->tm_mon;
+       tm.tm_mday = day_tm->tm_mday;
+       tm.tm_isdst = -1;
+       new_start_time = mktime(&tm);
+       i_assert(new_start_time != (time_t)-1);
+       return new_start_time;
+}
+
 static const char *strftime_real(const char *fmt, const struct tm *tm)
 {
        size_t bufsize = strlen(fmt) + 32;
index ef3643ce64ef0c3416f6b8b6ef3f7adca1e396c4..019da2aae4d667a0a7146df9dc29af2c1290d210 100644 (file)
@@ -36,6 +36,9 @@ timeval_sub_msecs(struct timeval *tv, unsigned int msecs)
        }
 }
 
+/* Convert t to local time and return timestamp on that day at 00:00:00. */
+time_t time_to_local_day_start(time_t t);
+
 /* Wrappers to strftime() */
 const char *t_strftime(const char *fmt, const struct tm *tm) ATTR_STRFTIME(1);
 const char *t_strflocaltime(const char *fmt, time_t t) ATTR_STRFTIME(1);