diff --git a/glib/gmain.c b/glib/gmain.c
index 1af9a5c..89526b0 100644
--- a/glib/gmain.c
+++ b/glib/gmain.c
@@ -3796,10 +3796,12 @@ static void
 g_timeout_set_expiration (GTimeoutSource *timeout_source,
                           gint64          current_time)
 {
-  timeout_source->expiration = current_time +
-                               (guint64) timeout_source->interval * 1000;
-
-  if (timeout_source->seconds)
+  if (!timeout_source->seconds)
+    {
+      timeout_source->expiration = current_time +
+                                   (guint64) timeout_source->interval * 1000;
+    }
+  else
     {
       static gint timer_perturb = -1;
 
@@ -3819,17 +3821,36 @@ g_timeout_set_expiration (GTimeoutSource *timeout_source,
             timer_perturb = 0;
         }
 
-      /* We want the microseconds part of the timeout to land on the
-       * 'timer_perturb' mark, but we need to make sure we don't try to
-       * set the timeout in the past.  We do this by ensuring that we
-       * always only *increase* the expiration time by adding a full
-       * second in the case that the microsecond portion decreases.
-       */
-      if (timer_perturb < timeout_source->expiration % 1000000)
-        timeout_source->expiration += 1000000;
+      if (timeout_source->expiration == 0)
+        {
+          /* the expiration has not been set yet */
+
+          timeout_source->expiration = current_time;
 
-      timeout_source->expiration =
-        ((timeout_source->expiration / 1000000) * 1000000) + timer_perturb;
+          /* We want the microseconds part of the timeout to land on the
+           * 'timer_perturb' mark, but we need to make sure we don't try to
+           * set the timeout in the past.  We do this by ensuring that we
+           * always only *increase* the expiration time by adding a full
+           * second in the case that the microsecond portion decreases.
+           */
+          if (timer_perturb < timeout_source->expiration % 1000000)
+            timeout_source->expiration += 1000000;
+
+          timeout_source->expiration =
+            ((timeout_source->expiration / 1000000) * 1000000) + timer_perturb;
+
+          timeout_source->expiration += (guint64) timeout_source->interval * 1000;
+         }
+
+      /* Once the expiration has been set to the timer_perturb fraction,
+       * we can just increment it by the required number of seconds without
+       * perturbing the perturb.
+       * Note that this is different from what we do for millisecond-granularity
+       * timers where we reschedule from current_time instead of the previous
+       * expiration. But since we are dealing with entire seconds here,
+       * this should hardly be noticable.
+       */
+      timeout_source->expiration += (guint64) timeout_source->interval * 1000;
     }
 }
 
