diff --git a/lib/shared/dm-ops/add-viewer-to-thread-members-spec.js b/lib/shared/dm-ops/add-viewer-to-thread-members-spec.js
--- a/lib/shared/dm-ops/add-viewer-to-thread-members-spec.js
+++ b/lib/shared/dm-ops/add-viewer-to-thread-members-spec.js
@@ -97,6 +97,13 @@
               subscription: joinThreadSubscription,
             })),
           ],
+          timestamps: {
+            ...existingThreadDetails.timestamps,
+            members: {
+              ...existingThreadDetails.timestamps.members,
+              ...memberTimestamps,
+            },
+          },
         },
         viewerID,
       );
@@ -105,16 +112,7 @@
           type: updateTypes.JOIN_THREAD,
           id: uuid.v4(),
           time,
-          threadInfo: {
-            ...resultThreadInfo,
-            timestamps: {
-              ...resultThreadInfo.timestamps,
-              members: {
-                ...resultThreadInfo.timestamps.members,
-                ...memberTimestamps,
-              },
-            },
-          },
+          threadInfo: resultThreadInfo,
           rawMessageInfos,
           truncationStatus: messageTruncationStatus.EXHAUSTIVE,
           rawEntryInfos: [],
diff --git a/lib/shared/dm-ops/create-sidebar-spec.js b/lib/shared/dm-ops/create-sidebar-spec.js
--- a/lib/shared/dm-ops/create-sidebar-spec.js
+++ b/lib/shared/dm-ops/create-sidebar-spec.js
@@ -21,6 +21,7 @@
   isInvalidSidebarSource,
   rawMessageInfoFromMessageData,
 } from '../message-utils.js';
+import { createThreadTimestamps } from '../thread-utils.js';
 
 async function createMessageDatasFromDMOperation(
   dmOperation: DMCreateSidebarOperation,
@@ -124,6 +125,7 @@
           unread: creatorID !== viewerID,
           sourceMessageID,
           containingThreadID: parentThreadID,
+          timestamps: createThreadTimestamps(time, allMemberIDs),
         },
         viewerID,
       );
diff --git a/lib/shared/dm-ops/create-thread-spec.js b/lib/shared/dm-ops/create-thread-spec.js
--- a/lib/shared/dm-ops/create-thread-spec.js
+++ b/lib/shared/dm-ops/create-thread-spec.js
@@ -77,6 +77,7 @@
     sourceMessageID,
     repliesCount,
     pinnedCount,
+    timestamps,
   } = input;
 
   const memberIDs = allMemberIDsWithSubscriptions.map(({ id }) => id);
@@ -117,7 +118,7 @@
     avatar,
     description,
     containingThreadID,
-    timestamps: createThreadTimestamps(creationTime, memberIDs),
+    timestamps,
   };
   if (sourceMessageID) {
     newThread.sourceMessageID = sourceMessageID;
@@ -180,6 +181,7 @@
           allMemberIDsWithSubscriptions,
           roleID,
           unread: creatorID !== viewerID,
+          timestamps: createThreadTimestamps(time, allMemberIDs),
         },
         viewerID,
       );
diff --git a/lib/shared/dm-ops/dm-op-utils.js b/lib/shared/dm-ops/dm-op-utils.js
--- a/lib/shared/dm-ops/dm-op-utils.js
+++ b/lib/shared/dm-ops/dm-op-utils.js
@@ -158,6 +158,7 @@
     sourceMessageID: threadInfo.sourceMessageID,
     repliesCount: threadInfo.repliesCount,
     pinnedCount: threadInfo.pinnedCount,
+    timestamps: threadInfo.timestamps,
   };
 }
 
diff --git a/lib/shared/dm-ops/join-thread-spec.js b/lib/shared/dm-ops/join-thread-spec.js
--- a/lib/shared/dm-ops/join-thread-spec.js
+++ b/lib/shared/dm-ops/join-thread-spec.js
@@ -107,6 +107,10 @@
             ...existingThreadDetails.allMemberIDsWithSubscriptions,
             { id: joinerID, subscription: joinThreadSubscription },
           ],
+          timestamps: {
+            ...existingThreadDetails.timestamps,
+            members: memberTimestamps,
+          },
         },
         viewerID,
       );
@@ -114,13 +118,7 @@
         type: updateTypes.JOIN_THREAD,
         id: uuid.v4(),
         time,
-        threadInfo: {
-          ...newThreadInfo,
-          timestamps: {
-            ...newThreadInfo.timestamps,
-            members: memberTimestamps,
-          },
-        },
+        threadInfo: newThreadInfo,
         rawMessageInfos: joinThreadMessageInfos,
         truncationStatus: messageTruncationStatus.EXHAUSTIVE,
         rawEntryInfos: [],
diff --git a/lib/types/dm-ops.js b/lib/types/dm-ops.js
--- a/lib/types/dm-ops.js
+++ b/lib/types/dm-ops.js
@@ -16,6 +16,10 @@
   type ThickThreadType,
   thickThreadTypeValidator,
 } from './thread-types-enum.js';
+import {
+  threadTimestampsValidator,
+  type ThreadTimestamps,
+} from './thread-types.js';
 import type { ClientUpdateInfo } from './update-types.js';
 import { values } from '../utils/objects.js';
 import { tColor, tShape, tString, tUserID } from '../utils/validation-utils.js';
@@ -55,6 +59,7 @@
   +allMemberIDsWithSubscriptions: $ReadOnlyArray<MemberIDWithSubscription>,
   +roleID: string,
   +unread: boolean,
+  +timestamps: ThreadTimestamps,
   +name?: ?string,
   +avatar?: ?ClientAvatar,
   +description?: ?string,
@@ -73,6 +78,7 @@
     allMemberIDsWithSubscriptions: t.list(memberIDWithSubscriptionValidator),
     roleID: t.String,
     unread: t.Boolean,
+    timestamps: threadTimestampsValidator,
     name: t.maybe(t.String),
     avatar: t.maybe(clientAvatarValidator),
     description: t.maybe(t.String),