(This is referring to the daily digests of all a person's stream activity - not those things coming from the Notifications system).

The logic is complex:
A) Send the digest email to a user at what is 5pm for each user, given their local timezone setting in their user profile;
i) Checked by, and performed during drupal cron
ii) Email is queued; actual delivery is throttled by the number of emails per cron configured in the admin interface.
B) Send information for Status Posts (and their follow-up comments) & activities starting from the time of their previous email until 8am of of the _current_ day.
i) The result is essentially to send them the activity from the _prior_ day.
ii) For example, the email sent to me at 5pm on 10 Aug contains _new_ status wall entries & activities starting at 5pm on 8 August until 8am 10 August.
iii) The purpose of this is so that the digest emails will contain status posts PLUS associated comments.
a) If, alternately, we were to have the 5pm-10Aug email contain status wall posts that were made during the day of 10Aug, there would likely be few "comments" on status posts, and so threads of conversations will be missed.
C) Note that we believe this is the strategy used by Yammer.

COMMENT) It is arguable whether the time of email sending should be at the beginning of the day, vs. the end. E.g. in the example above, I would receive email at 8am 10 Aug containing status posts & activity from 5pm 8 Aug up until 8am 10 Aug. BUT, this is likely to lose comments from status posts made at 5pm 9 Aug, which is why this is a less-desirable strategy.

Comments

icecreamyou’s picture

It's a little less complicated, I think, than it appears to be in your head. :-)

By default, digest emails are sent during cron runs some time after 6PM in the user's current time zone. The digest emails contain activity messages created between 6PM two days ago and 6PM one day ago. These activity messages may include comments on statuses that were made any time before the email was sent (e.g. before approximately 6PM today).

The bug here is that on Acquia's intranet people are getting the emails at 2PM instead of at 6PM. I don't know if anyone has confirmed this outside of the intranet; I haven't. Without confirmation, it's hard to know whether this is really just a problem with the server's time or whether it's a problem with the module. Either way, seems like a minor problem to me, since there is an obvious work-around: set the send time to 10PM.

This is the logic that determines what time a digest email gets sent:

  $default_tz = variable_get('date_default_timezone', 0);
  $now = time();
  $send_time = mktime(variable_get('digests_send_time', 18), 0, 0);

  // Step 1: Get users for whom it is after 6PM in their timezone but who have not had a digest sent for this interval.
  $default = $now > $send_time + $default_tz || $now < $send_time + $default_tz - 43200; // whether it's past send_time in the site's default timezone
  $query = "
    SELECT d.*, u.* /* We need the digests table first here, otherwise users with no digests row have uid = NULL in the results */
    FROM {users} u
    LEFT JOIN {digests} d
      ON u.uid = d.uid
    WHERE
      status = 1 AND (                                                  /* user is not blocked */
        send_interval IS NULL OR                                        /* user has not set their interval */
        send_interval = 86400                                           /* user's interval is daily */
        ". (date('w') == 0 ? 'OR send_interval = 604800' : '') ."       /* user's interval is weekly, and it's Sunday */
      ) AND
      %d > COALESCE(last_sent, created) + (COALESCE(send_interval, 86400) - 43200) /* it's been at least (interval - 12 hours) since the last digest email */
  ";
  if (variable_get('digests_local', 'local') == 'local') {
    $query .= " AND (
        %d /* NOW */ > %d /* SEND */ + timezone OR      /* it's after send_time today */
        %d /* NOW */ < %d /* SEND */ + timezone - 43200 /* it's more than 12hrs before send_time today, i.e. less than 12hrs since send_time yesterday */
    ";
    if ($default) {
      $query .= "    OR timezone IS NULL /* the user has not set a timezone, fall back to the site default */";
    }
    $query .= "\n      )";
    if (variable_get('digests_limit', 250)) {
      $result = db_query_range($query, $now, $now, $send_time, $now, $send_time, 0, variable_get('digests_limit', 250));
    }
    else {
      $result = db_query($query, $now, $now, $send_time, $now, $send_time);
    }
  }
  elseif ($default) {
    if (variable_get('digests_limit', 250)) {
      $result = db_query_range($query, $now, 0, variable_get('digests_limit', 250));
    }
    else {
      $result = db_query($query, $now);
    }
  }

I really can't identify a problem in it. Everything looks like it should be working to me.

icecreamyou’s picture

Status: Active » Fixed

The reason this is happening is that mktime() takes the server time zone into account, so mktime(18, 0, 0) returns 6PM *server time* not 6PM GMT as I had thought. The solution is simple: use gmmktime() instead.

Committed fix: https://github.com/acquia/commons/commit/7606f99e289713dae903624f1ad80c3...

Automatically closed -- issue fixed for 2 weeks with no activity.