Bug 1107308 - Round dateAdded and lastModified values to milliseconds precision in places cpp components. r=mak
authorAsaf Romano <mano@mozilla.com>
Thu, 04 Dec 2014 14:09:48 -0800
changeset 219138 a39fcc75eb5ead33bf319323fe35ac0afcf83c3f
parent 219137 0f7e5b1c4b622e8ad431630f24c7d1ac4f6458a8
child 219139 806ccfabfbdeaaeb224ac3fc3529a8e1579159b9
push id27956
push userkwierso@gmail.com
push dateFri, 12 Dec 2014 00:47:19 +0000
treeherdermozilla-central@32a2c5bd2f68 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmak
bugs1107308
milestone37.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1107308 - Round dateAdded and lastModified values to milliseconds precision in places cpp components. r=mak
toolkit/components/places/Database.cpp
toolkit/components/places/Database.h
toolkit/components/places/Helpers.cpp
toolkit/components/places/Helpers.h
toolkit/components/places/nsAnnotationService.cpp
toolkit/components/places/nsINavBookmarksService.idl
toolkit/components/places/nsNavBookmarks.cpp
toolkit/components/places/nsNavHistoryResult.cpp
toolkit/components/places/tests/bookmarks/test_bookmarks.js
toolkit/components/places/tests/head_common.js
toolkit/components/places/tests/migration/places_v25.sqlite
toolkit/components/places/tests/migration/places_v26.sqlite
toolkit/components/places/tests/migration/test_current_from_v25.js
toolkit/components/places/tests/migration/xpcshell.ini
toolkit/components/places/tests/queries/test_sorting.js
toolkit/components/places/tests/unit/test_398914.js
toolkit/components/places/tests/unit/test_419731.js
toolkit/components/places/tests/unit/test_lastModified.js
toolkit/components/places/tests/unit/test_placesTxn.js
--- a/toolkit/components/places/Database.cpp
+++ b/toolkit/components/places/Database.cpp
@@ -264,17 +264,17 @@ CreateRoot(nsCOMPtr<mozIStorageConnectio
 
   // The position of the new item in its folder.
   static int32_t itemPosition = 0;
 
   // A single creation timestamp for all roots so that the root folder's
   // last modification time isn't earlier than its childrens' creation time.
   static PRTime timestamp = 0;
   if (!timestamp)
-    timestamp = PR_Now();
+    timestamp = RoundedPRNow();
 
   // Create a new bookmark folder for the root.
   nsCOMPtr<mozIStorageStatement> stmt;
   nsresult rv = aDBConn->CreateStatement(NS_LITERAL_CSTRING(
     "INSERT INTO moz_bookmarks "
       "(type, position, title, dateAdded, lastModified, guid, parent) "
     "VALUES (:item_type, :item_position, :item_title,"
             ":date_added, :last_modified, :guid,"
@@ -723,16 +723,23 @@ Database::InitSchema(bool* aDatabaseMigr
 
       if (currentSchemaVersion < 25) {
         rv = MigrateV25Up();
         NS_ENSURE_SUCCESS(rv, rv);
       }
 
       // Firefox 36 uses schema version 25.
 
+      if (currentSchemaVersion < 26) {
+        rv = MigrateV26Up();
+        NS_ENSURE_SUCCESS(rv, rv);
+      }
+
+      // Firefox 37 uses schema version 26.
+
       // Schema Upgrades must add migration code here.
 
       rv = UpdateBookmarkRootTitles();
       // We don't want a broken localization to cause us to think
       // the database is corrupt and needs to be replaced.
       MOZ_ASSERT(NS_SUCCEEDED(rv));
     }
   }
@@ -1462,16 +1469,29 @@ Database::MigrateV25Up()
 
     rv = stmt->Execute();
     NS_ENSURE_SUCCESS(rv, rv);
   }
 
   return NS_OK;
 }
 
+nsresult
+Database::MigrateV26Up() {
+  MOZ_ASSERT(NS_IsMainThread());
+
+  // Round down dateAdded and lastModified values to milliseconds precision.
+  nsresult rv = mMainConn->ExecuteSimpleSQL(NS_LITERAL_CSTRING(
+    "UPDATE moz_bookmarks SET dateAdded = dateAdded - dateAdded % 1000, "
+    "                         lastModified = lastModified - lastModified % 1000"));
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  return NS_OK;
+}
+
 void
 Database::Shutdown()
 {
   MOZ_ASSERT(NS_IsMainThread());
   MOZ_ASSERT(!mShuttingDown);
   MOZ_ASSERT(!mClosed);
 
   mShuttingDown = true;
@@ -1575,16 +1595,32 @@ Database::Observe(nsISupports *aSubject,
         "FROM moz_favicons "
         "WHERE guid IS NULL "
       ), getter_AddRefs(stmt));
       NS_ENSURE_SUCCESS(rv, rv);
       rv = stmt->ExecuteStep(&haveNullGuids);
       NS_ENSURE_SUCCESS(rv, rv);
       MOZ_ASSERT(!haveNullGuids && "Found a favicon without a GUID!");
     }
+
+    { // Sanity check for unrounded dateAdded and lastModified values (bug
+      // 1107308).
+      bool hasUnroundedDates = false;
+      nsCOMPtr<mozIStorageStatement> stmt;
+
+      nsresult rv = mMainConn->CreateStatement(NS_LITERAL_CSTRING(
+        "SELECT 1 "
+        "FROM moz_bookmarks "
+        "WHERE dateAdded % 1000 > 0 OR lastModified % 1000 > 0 LIMIT 1"
+      ), getter_AddRefs(stmt));
+      NS_ENSURE_SUCCESS(rv, rv);
+      rv = stmt->ExecuteStep(&hasUnroundedDates);
+      NS_ENSURE_SUCCESS(rv, rv);
+      MOZ_ASSERT(!hasUnroundedDates && "Found unrounded dates!");
+    }
 #endif
 
     // As the last step in the shutdown path, finalize the database handle.
     Shutdown();
   }
 
   return NS_OK;
 }
--- a/toolkit/components/places/Database.h
+++ b/toolkit/components/places/Database.h
@@ -11,17 +11,17 @@
 #include "nsIObserver.h"
 #include "mozilla/storage.h"
 #include "mozilla/storage/StatementCache.h"
 #include "mozilla/Attributes.h"
 #include "nsIEventTarget.h"
 
 // This is the schema version. Update it at any schema change and add a
 // corresponding migrateVxx method below.
-#define DATABASE_SCHEMA_VERSION 25
+#define DATABASE_SCHEMA_VERSION 26
 
 // Fired after Places inited.
 #define TOPIC_PLACES_INIT_COMPLETE "places-init-complete"
 // Fired when initialization fails due to a locked database.
 #define TOPIC_DATABASE_LOCKED "places-database-locked"
 // This topic is received when the profile is about to be lost.  Places does
 // initial shutdown work and notifies TOPIC_PLACES_SHUTDOWN to all listeners.
 // Any shutdown work that requires the Places APIs should happen here.
@@ -268,16 +268,17 @@ protected:
   nsresult MigrateV18Up();
   nsresult MigrateV19Up();
   nsresult MigrateV20Up();
   nsresult MigrateV21Up();
   nsresult MigrateV22Up();
   nsresult MigrateV23Up();
   nsresult MigrateV24Up();
   nsresult MigrateV25Up();
+  nsresult MigrateV26Up();
 
   nsresult UpdateBookmarkRootTitles();
 
 private:
   ~Database();
 
   /**
    * Singleton getter, invoked by class instantiation.
--- a/toolkit/components/places/Helpers.cpp
+++ b/toolkit/components/places/Helpers.cpp
@@ -316,16 +316,26 @@ void
 TruncateTitle(const nsACString& aTitle, nsACString& aTrimmed)
 {
   aTrimmed = aTitle;
   if (aTitle.Length() > TITLE_LENGTH_MAX) {
     aTrimmed = StringHead(aTitle, TITLE_LENGTH_MAX);
   }
 }
 
+PRTime
+RoundToMilliseconds(PRTime aTime) {
+  return aTime - (aTime % PR_USEC_PER_MSEC);
+}
+
+PRTime
+RoundedPRNow() {
+  return RoundToMilliseconds(PR_Now());
+}
+
 void
 ForceWALCheckpoint()
 {
   nsRefPtr<Database> DB = Database::GetDatabase();
   if (DB) {
     nsCOMPtr<mozIStorageAsyncStatement> stmt = DB->GetAsyncStatement(
       "pragma wal_checkpoint "
     );
--- a/toolkit/components/places/Helpers.h
+++ b/toolkit/components/places/Helpers.h
@@ -9,16 +9,17 @@
 /**
  * This file contains helper classes used by various bits of Places code.
  */
 
 #include "mozilla/storage.h"
 #include "nsIURI.h"
 #include "nsThreadUtils.h"
 #include "nsProxyRelease.h"
+#include "prtime.h"
 #include "mozilla/Telemetry.h"
 
 namespace mozilla {
 namespace places {
 
 ////////////////////////////////////////////////////////////////////////////////
 //// Asynchronous Statement Callback Helper
 
@@ -144,16 +145,32 @@ bool IsValidGUID(const nsACString& aGUID
  * @param aTitle
  *        The title to truncate (if necessary)
  * @param aTrimmed
  *        Output parameter to return the trimmed string
  */
 void TruncateTitle(const nsACString& aTitle, nsACString& aTrimmed);
 
 /**
+ * Round down a PRTime value to milliseconds precision (...000).
+ *
+ * @param aTime
+ *        a PRTime value.
+ * @return aTime rounded down to milliseconds precision.
+ */
+PRTime RoundToMilliseconds(PRTime aTime);
+
+/**
+ * Round down PR_Now() to milliseconds precision.
+ *
+ * @return @see PR_Now, RoundToMilliseconds.
+ */
+PRTime RoundedPRNow();
+
+/**
  * Used to finalize a statementCache on a specified thread.
  */
 template<typename StatementType>
 class FinalizeStatementCacheProxy : public nsRunnable
 {
 public:
   /**
    * Constructor.
--- a/toolkit/components/places/nsAnnotationService.cpp
+++ b/toolkit/components/places/nsAnnotationService.cpp
@@ -1912,32 +1912,32 @@ nsAnnotationService::StartSetAnnotation(
     rv = aStatement->BindInt64ByName(NS_LITERAL_CSTRING("id"), oldAnnoId);
     NS_ENSURE_SUCCESS(rv, rv);
     rv = aStatement->BindInt64ByName(NS_LITERAL_CSTRING("date_added"), oldAnnoDate);
     NS_ENSURE_SUCCESS(rv, rv);
   }
   else {
     rv = aStatement->BindNullByName(NS_LITERAL_CSTRING("id"));
     NS_ENSURE_SUCCESS(rv, rv);
-    rv = aStatement->BindInt64ByName(NS_LITERAL_CSTRING("date_added"), PR_Now());
+    rv = aStatement->BindInt64ByName(NS_LITERAL_CSTRING("date_added"), RoundedPRNow());
     NS_ENSURE_SUCCESS(rv, rv);
   }
 
   rv = aStatement->BindInt64ByName(NS_LITERAL_CSTRING("fk"), fkId);
   NS_ENSURE_SUCCESS(rv, rv);
   rv = aStatement->BindInt64ByName(NS_LITERAL_CSTRING("name_id"), nameID);
   NS_ENSURE_SUCCESS(rv, rv);
 
   rv = aStatement->BindInt32ByName(NS_LITERAL_CSTRING("flags"), aFlags);
   NS_ENSURE_SUCCESS(rv, rv);
   rv = aStatement->BindInt32ByName(NS_LITERAL_CSTRING("expiration"), aExpiration);
   NS_ENSURE_SUCCESS(rv, rv);
   rv = aStatement->BindInt32ByName(NS_LITERAL_CSTRING("type"), aType);
   NS_ENSURE_SUCCESS(rv, rv);
-  rv = aStatement->BindInt64ByName(NS_LITERAL_CSTRING("last_modified"), PR_Now());
+  rv = aStatement->BindInt64ByName(NS_LITERAL_CSTRING("last_modified"), RoundedPRNow());
   NS_ENSURE_SUCCESS(rv, rv);
 
   // On success, leave the statement open, the caller will set the value
   // and execute the statement.
   setAnnoScoper.Abandon();
 
   return NS_OK;
 }
--- a/toolkit/components/places/nsINavBookmarksService.idl
+++ b/toolkit/components/places/nsINavBookmarksService.idl
@@ -403,37 +403,61 @@ interface nsINavBookmarksService : nsISu
    *  @param aItemId
    *         The id of the item whose title should be retrieved
    *  @return The title of the item.
    */
   AUTF8String getItemTitle(in long long aItemId);
 
   /**
    * Set the date added time for an item.
+   *
+   * @param aItemId
+   *        the id of the item whose date added time should be updated.
+   * @param aDateAdded
+   *        the new date added value in microseconds.  Note that it is rounded
+   *        down to milliseconds precision.
    */
   void setItemDateAdded(in long long aItemId, in PRTime aDateAdded);
+
   /**
    * Get the date added time for an item.
+   *
+   * @param aItemId
+   *        the id of the item whose date added time should be retrieved.
+   *
+   * @return the date added value in microseconds.
    */
   PRTime getItemDateAdded(in long long aItemId);
 
   /**
    * Set the last modified time for an item.
    *
-   *  @note This is the only method that will send an itemChanged notification
-   *        for the property.  lastModified will still be updated in
-   *        any other method that changes an item property, but we will send
-   *        the corresponding itemChanged notification instead.
+   * @param aItemId
+   *        the id of the item whose last modified time should be updated.
+   * @param aLastModified
+   *        the new last modified value in microseconds.  Note that it is
+   *        rounded down to milliseconds precision.
+   *
+   * @note This is the only method that will send an itemChanged notification
+   *       for the property.  lastModified will still be updated in
+   *       any other method that changes an item property, but we will send
+   *       the corresponding itemChanged notification instead.
    */
   void setItemLastModified(in long long aItemId, in PRTime aLastModified);
+
   /**
    * Get the last modified time for an item.
    *
-   *  @note When an item is added lastModified is set to the same value as
-   *        dateAdded.
+   * @param aItemId
+   *        the id of the item whose last modified time should be retrieved.
+   *
+   * @return the date added value in microseconds.
+   *
+   * @note When an item is added lastModified is set to the same value as
+   *       dateAdded.
    */
   PRTime getItemLastModified(in long long aItemId);
 
   /**
    * Get the URI for a bookmark item.
    */
   nsIURI getBookmarkURI(in long long aItemId);
 
--- a/toolkit/components/places/nsNavBookmarks.cpp
+++ b/toolkit/components/places/nsNavBookmarks.cpp
@@ -521,17 +521,17 @@ nsNavBookmarks::InsertBookmark(int64_t a
   else {
     index = aIndex;
     // Create space for the insertion.
     rv = AdjustIndices(aFolder, index, INT32_MAX, 1);
     NS_ENSURE_SUCCESS(rv, rv);
   }
 
   *aNewBookmarkId = -1;
-  PRTime dateAdded = PR_Now();
+  PRTime dateAdded = RoundedPRNow();
   nsAutoCString guid(aGUID);
   nsCString title;
   TruncateTitle(aTitle, title);
 
   rv = InsertBookmarkInDB(placeId, BOOKMARK, aFolder, index, title, dateAdded,
                           0, folderGuid, grandParentId, aURI,
                           aNewBookmarkId, guid);
   NS_ENSURE_SUCCESS(rv, rv);
@@ -623,17 +623,17 @@ nsNavBookmarks::RemoveItem(int64_t aItem
 
   // Fix indices in the parent.
   if (bookmark.position != DEFAULT_INDEX) {
     rv = AdjustIndices(bookmark.parentId,
                        bookmark.position + 1, INT32_MAX, -1);
     NS_ENSURE_SUCCESS(rv, rv);
   }
 
-  bookmark.lastModified = PR_Now();
+  bookmark.lastModified = RoundedPRNow();
   rv = SetItemDateInternal(LAST_MODIFIED, bookmark.parentId,
                            bookmark.lastModified);
   NS_ENSURE_SUCCESS(rv, rv);
 
   rv = transaction.Commit();
   NS_ENSURE_SUCCESS(rv, rv);
 
   nsCOMPtr<nsIURI> uri;
@@ -751,17 +751,17 @@ nsNavBookmarks::CreateContainerWithID(in
   } else {
     index = *aIndex;
     // Create space for the insertion.
     rv = AdjustIndices(aParent, index, INT32_MAX, 1);
     NS_ENSURE_SUCCESS(rv, rv);
   }
 
   *aNewFolder = aItemId;
-  PRTime dateAdded = PR_Now();
+  PRTime dateAdded = RoundedPRNow();
   nsAutoCString guid(aGUID);
   nsCString title;
   TruncateTitle(aTitle, title);
 
   rv = InsertBookmarkInDB(-1, FOLDER, aParent, index,
                           title, dateAdded, 0, folderGuid, grandParentId,
                           nullptr, aNewFolder, guid);
   NS_ENSURE_SUCCESS(rv, rv);
@@ -812,17 +812,17 @@ nsNavBookmarks::InsertSeparator(int64_t 
     NS_ENSURE_SUCCESS(rv, rv);
   }
 
   *aNewItemId = -1;
   // Set a NULL title rather than an empty string.
   nsCString voidString;
   voidString.SetIsVoid(true);
   nsAutoCString guid(aGUID);
-  PRTime dateAdded = PR_Now();
+  PRTime dateAdded = RoundedPRNow();
   rv = InsertBookmarkInDB(-1, SEPARATOR, aParent, index, voidString, dateAdded,
                           0, folderGuid, grandParentId, nullptr,
                           aNewItemId, guid);
   NS_ENSURE_SUCCESS(rv, rv);
 
   rv = transaction.Commit();
   NS_ENSURE_SUCCESS(rv, rv);
 
@@ -1100,17 +1100,17 @@ nsNavBookmarks::RemoveFolderChildren(int
       "DELETE FROM moz_items_annos "
       "WHERE id IN ("
         "SELECT a.id from moz_items_annos a "
         "LEFT JOIN moz_bookmarks b ON a.item_id = b.id "
         "WHERE b.id ISNULL)"));
   NS_ENSURE_SUCCESS(rv, rv);
 
   // Set the lastModified date.
-  rv = SetItemDateInternal(LAST_MODIFIED, folder.id, PR_Now());
+  rv = SetItemDateInternal(LAST_MODIFIED, folder.id, RoundedPRNow());
   NS_ENSURE_SUCCESS(rv, rv);
 
   for (uint32_t i = 0; i < folderChildrenArray.Length(); i++) {
     BookmarkData& child = folderChildrenArray[i];
     if (child.type == TYPE_BOOKMARK) {
       // If not a tag, recalculate frecency for this entry, since it changed.
       if (child.grandParentId != mTagsRoot) {
         nsNavHistory* history = nsNavHistory::GetHistoryService();
@@ -1284,17 +1284,17 @@ nsNavBookmarks::MoveItem(int64_t aItemId
     rv = stmt->BindInt32ByName(NS_LITERAL_CSTRING("item_index"), newIndex);
     NS_ENSURE_SUCCESS(rv, rv);
     rv = stmt->BindInt64ByName(NS_LITERAL_CSTRING("item_id"), bookmark.id);
     NS_ENSURE_SUCCESS(rv, rv);
     rv = stmt->Execute();
     NS_ENSURE_SUCCESS(rv, rv);
   }
 
-  PRTime now = PR_Now();
+  PRTime now = RoundedPRNow();
   rv = SetItemDateInternal(LAST_MODIFIED, bookmark.parentId, now);
   NS_ENSURE_SUCCESS(rv, rv);
   rv = SetItemDateInternal(LAST_MODIFIED, aNewParent, now);
   NS_ENSURE_SUCCESS(rv, rv);
 
   rv = transaction.Commit();
   NS_ENSURE_SUCCESS(rv, rv);
 
@@ -1381,16 +1381,18 @@ nsNavBookmarks::FetchItemInfo(int64_t aI
   return NS_OK;
 }
 
 nsresult
 nsNavBookmarks::SetItemDateInternal(enum BookmarkDate aDateType,
                                     int64_t aItemId,
                                     PRTime aValue)
 {
+  aValue = RoundToMilliseconds(aValue);
+
   nsCOMPtr<mozIStorageStatement> stmt;
   if (aDateType == DATE_ADDED) {
     // lastModified is set to the same value as dateAdded.  We do this for
     // performance reasons, since it will allow us to use an index to sort items
     // by date.
     stmt = mDB->GetStatement(
       "UPDATE moz_bookmarks SET dateAdded = :date, lastModified = :date "
       "WHERE id = :item_id"
@@ -1422,17 +1424,19 @@ nsNavBookmarks::SetItemDateInternal(enum
 NS_IMETHODIMP
 nsNavBookmarks::SetItemDateAdded(int64_t aItemId, PRTime aDateAdded)
 {
   NS_ENSURE_ARG_MIN(aItemId, 1);
 
   BookmarkData bookmark;
   nsresult rv = FetchItemInfo(aItemId, bookmark);
   NS_ENSURE_SUCCESS(rv, rv);
-  bookmark.dateAdded = aDateAdded;
+
+  // Round here so that we notify with the right value.
+  bookmark.dateAdded = RoundToMilliseconds(aDateAdded);
 
   rv = SetItemDateInternal(DATE_ADDED, bookmark.id, bookmark.dateAdded);
   NS_ENSURE_SUCCESS(rv, rv);
 
   // Note: mDBSetItemDateAdded also sets lastModified to aDateAdded.
   NOTIFY_OBSERVERS(mCanNotify, mCacheObservers, mObservers,
                    nsINavBookmarkObserver,
                    OnItemChanged(bookmark.id,
@@ -1466,17 +1470,19 @@ nsNavBookmarks::GetItemDateAdded(int64_t
 NS_IMETHODIMP
 nsNavBookmarks::SetItemLastModified(int64_t aItemId, PRTime aLastModified)
 {
   NS_ENSURE_ARG_MIN(aItemId, 1);
 
   BookmarkData bookmark;
   nsresult rv = FetchItemInfo(aItemId, bookmark);
   NS_ENSURE_SUCCESS(rv, rv);
-  bookmark.lastModified = aLastModified;
+
+  // Round here so that we notify with the right value.
+  bookmark.lastModified = RoundToMilliseconds(aLastModified);
 
   rv = SetItemDateInternal(LAST_MODIFIED, bookmark.id, bookmark.lastModified);
   NS_ENSURE_SUCCESS(rv, rv);
 
   // Note: mDBSetItemDateAdded also sets lastModified to aDateAdded.
   NOTIFY_OBSERVERS(mCanNotify, mCacheObservers, mObservers,
                    nsINavBookmarkObserver,
                    OnItemChanged(bookmark.id,
@@ -1530,17 +1536,17 @@ nsNavBookmarks::SetItemTitle(int64_t aIt
   if (title.IsVoid()) {
     rv = statement->BindNullByName(NS_LITERAL_CSTRING("item_title"));
   }
   else {
     rv = statement->BindUTF8StringByName(NS_LITERAL_CSTRING("item_title"),
                                          title);
   }
   NS_ENSURE_SUCCESS(rv, rv);
-  bookmark.lastModified = PR_Now();
+  bookmark.lastModified = RoundToMilliseconds(RoundedPRNow());
   rv = statement->BindInt64ByName(NS_LITERAL_CSTRING("date"),
                                   bookmark.lastModified);
   NS_ENSURE_SUCCESS(rv, rv);
   rv = statement->BindInt64ByName(NS_LITERAL_CSTRING("item_id"), bookmark.id);
   NS_ENSURE_SUCCESS(rv, rv);
 
   rv = statement->Execute();
   NS_ENSURE_SUCCESS(rv, rv);
@@ -1999,17 +2005,17 @@ nsNavBookmarks::ChangeBookmarkURI(int64_
     "UPDATE moz_bookmarks SET fk = :page_id, lastModified = :date "
     "WHERE id = :item_id "
   );
   NS_ENSURE_STATE(statement);
   mozStorageStatementScoper scoper(statement);
 
   rv = statement->BindInt64ByName(NS_LITERAL_CSTRING("page_id"), newPlaceId);
   NS_ENSURE_SUCCESS(rv, rv);
-  bookmark.lastModified = PR_Now();
+  bookmark.lastModified = RoundedPRNow();
   rv = statement->BindInt64ByName(NS_LITERAL_CSTRING("date"),
                                   bookmark.lastModified);
   NS_ENSURE_SUCCESS(rv, rv);
   rv = statement->BindInt64ByName(NS_LITERAL_CSTRING("item_id"), bookmark.id);
   NS_ENSURE_SUCCESS(rv, rv);
   rv = statement->Execute();
   NS_ENSURE_SUCCESS(rv, rv);
 
@@ -2355,17 +2361,17 @@ nsNavBookmarks::SetKeywordForBookmark(in
 
     // Add new keyword association to the hash, removing the old one if needed.
     if (!oldKeyword.IsEmpty())
       mBookmarkToKeywordHash.Remove(bookmark.id);
     mBookmarkToKeywordHash.Put(bookmark.id, keyword);
     rv = updateBookmarkStmt->BindStringByName(NS_LITERAL_CSTRING("keyword"), keyword);
   }
   NS_ENSURE_SUCCESS(rv, rv);
-  bookmark.lastModified = PR_Now();
+  bookmark.lastModified = RoundedPRNow();
   rv = updateBookmarkStmt->BindInt64ByName(NS_LITERAL_CSTRING("date"),
                                            bookmark.lastModified);
   NS_ENSURE_SUCCESS(rv, rv);
   rv = updateBookmarkStmt->BindInt64ByName(NS_LITERAL_CSTRING("item_id"),
                                            bookmark.id);
   NS_ENSURE_SUCCESS(rv, rv);
   rv = updateBookmarkStmt->Execute();
   NS_ENSURE_SUCCESS(rv, rv);
@@ -2830,17 +2836,17 @@ nsNavBookmarks::OnPageAnnotationSet(nsIU
 
 NS_IMETHODIMP
 nsNavBookmarks::OnItemAnnotationSet(int64_t aItemId, const nsACString& aName)
 {
   BookmarkData bookmark;
   nsresult rv = FetchItemInfo(aItemId, bookmark);
   NS_ENSURE_SUCCESS(rv, rv);
 
-  bookmark.lastModified = PR_Now();
+  bookmark.lastModified = RoundedPRNow();
   rv = SetItemDateInternal(LAST_MODIFIED, bookmark.id, bookmark.lastModified);
   NS_ENSURE_SUCCESS(rv, rv);
 
   NOTIFY_OBSERVERS(mCanNotify, mCacheObservers, mObservers,
                    nsINavBookmarkObserver,
                    OnItemChanged(bookmark.id,
                                  aName,
                                  true,
--- a/toolkit/components/places/nsNavHistoryResult.cpp
+++ b/toolkit/components/places/nsNavHistoryResult.cpp
@@ -3915,17 +3915,17 @@ nsNavHistoryFolderResultNode::OnItemMove
       NS_ENSURE_SUCCESS(rv, rv);
     }
     if (aOldParent == mTargetFolderItemId) {
       OnItemRemoved(aItemId, aOldParent, aOldIndex, aItemType, itemURI,
                     aGUID, aOldParentGUID);
     }
     if (aNewParent == mTargetFolderItemId) {
       OnItemAdded(aItemId, aNewParent, aNewIndex, aItemType, itemURI, itemTitle,
-                  PR_Now(), // This is a dummy dateAdded, not the real value.
+                  RoundedPRNow(), // This is a dummy dateAdded, not the real value.
                   aGUID, aNewParentGUID);
     }
   }
   return NS_OK;
 }
 
 
 /**
--- a/toolkit/components/places/tests/bookmarks/test_bookmarks.js
+++ b/toolkit/components/places/tests/bookmarks/test_bookmarks.js
@@ -144,18 +144,20 @@ add_task(function test_bookmarks() {
   do_check_eq(lastModified, dateAdded);
 
   // The time before we set the title, in microseconds.
   let beforeSetTitle = Date.now() * 1000;
   do_check_true(beforeSetTitle >= beforeInsert);
 
   // Workaround possible VM timers issues moving lastModified and dateAdded
   // to the past.
-  bs.setItemLastModified(newId, --lastModified);
-  bs.setItemDateAdded(newId, --dateAdded);
+  lastModified -= 1000;
+  bs.setItemLastModified(newId, lastModified);
+  dateAdded -= 1000;
+  bs.setItemDateAdded(newId, dateAdded);
 
   // set bookmark title
   bs.setItemTitle(newId, "Google");
   do_check_eq(bookmarksObserver._itemChangedId, newId);
   do_check_eq(bookmarksObserver._itemChangedProperty, "title");
   do_check_eq(bookmarksObserver._itemChangedValue, "Google");
 
   // check that dateAdded hasn't changed
@@ -322,18 +324,20 @@ add_task(function test_bookmarks() {
   try {
     let dateAdded = bs.getItemDateAdded(kwTestItemId);
     // after just inserting, modified should not be set
     let lastModified = bs.getItemLastModified(kwTestItemId);
     do_check_eq(lastModified, dateAdded);
 
     // Workaround possible VM timers issues moving lastModified and dateAdded
     // to the past.
+    lastModified -= 1000;
     bs.setItemLastModified(kwTestItemId, --lastModified);
-    bs.setItemDateAdded(kwTestItemId, --dateAdded);
+    dateAdded -= 1000;
+    bs.setItemDateAdded(kwTestItemId, dateAdded);
 
     bs.setKeywordForBookmark(kwTestItemId, "bar");
 
     let lastModified2 = bs.getItemLastModified(kwTestItemId);
     LOG("test setKeywordForBookmark");
     LOG("dateAdded = " + dateAdded);
     LOG("lastModified = " + lastModified);
     LOG("lastModified2 = " + lastModified2);
@@ -449,18 +453,20 @@ add_task(function test_bookmarks() {
                                   bs.DEFAULT_INDEX, "");
   dateAdded = bs.getItemDateAdded(newId10);
   // after just inserting, modified should not be set
   lastModified = bs.getItemLastModified(newId10);
   do_check_eq(lastModified, dateAdded);
 
   // Workaround possible VM timers issues moving lastModified and dateAdded
   // to the past.
-  bs.setItemLastModified(newId10, --lastModified);
-  bs.setItemDateAdded(newId10, --dateAdded);
+  lastModified -= 1000;
+  bs.setItemLastModified(newId10, lastModified);
+  dateAdded -= 1000;
+  bs.setItemDateAdded(newId10, dateAdded);
 
   bs.changeBookmarkURI(newId10, uri("http://foo11.com/"));
 
   // check that lastModified is set after we change the bookmark uri
   lastModified2 = bs.getItemLastModified(newId10);
   LOG("test changeBookmarkURI");
   LOG("dateAdded = " + dateAdded);
   LOG("lastModified = " + lastModified);
@@ -591,22 +597,22 @@ add_task(function test_bookmarks() {
   }
 
   // check setItemLastModified() and setItemDateAdded()
   let newId14 = bs.insertBookmark(testRoot, uri("http://bar.tld/"),
                                   bs.DEFAULT_INDEX, "");
   dateAdded = bs.getItemDateAdded(newId14);
   lastModified = bs.getItemLastModified(newId14);
   do_check_eq(lastModified, dateAdded);
-  bs.setItemLastModified(newId14, 1234);
+  bs.setItemLastModified(newId14, 1234000000000000);
   let fakeLastModified = bs.getItemLastModified(newId14);
-  do_check_eq(fakeLastModified, 1234);
-  bs.setItemDateAdded(newId14, 4321);
+  do_check_eq(fakeLastModified, 1234000000000000);
+  bs.setItemDateAdded(newId14, 4321000000000000);
   let fakeDateAdded = bs.getItemDateAdded(newId14);
-  do_check_eq(fakeDateAdded, 4321);
+  do_check_eq(fakeDateAdded, 4321000000000000);
   
   // ensure that removing an item removes its annotations
   do_check_true(anno.itemHasAnnotation(newId3, "test-annotation"));
   bs.removeItem(newId3);
   do_check_false(anno.itemHasAnnotation(newId3, "test-annotation"));
 
   // bug 378820
   let uri1 = uri("http://foo.tld/a");
--- a/toolkit/components/places/tests/head_common.js
+++ b/toolkit/components/places/tests/head_common.js
@@ -1,14 +1,14 @@
 /* -*- indent-tabs-mode: nil; js-indent-level: 2 -*-
  * This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
-const CURRENT_SCHEMA_VERSION = 25;
+const CURRENT_SCHEMA_VERSION = 26;
 const FIRST_UPGRADABLE_SCHEMA_VERSION = 11;
 
 const NS_APP_USER_PROFILE_50_DIR = "ProfD";
 const NS_APP_PROFILE_DIR_STARTUP = "ProfDS";
 
 // Shortcuts to transitions type.
 const TRANSITION_LINK = Ci.nsINavHistoryService.TRANSITION_LINK;
 const TRANSITION_TYPED = Ci.nsINavHistoryService.TRANSITION_TYPED;
index ef5e1def9b7f5a5c6495a5c3ac5eb76cb6a6038b..2afd1da1fd7ce40cda051975bb26d4a3223ff4b8
GIT binary patch
literal 1179648
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
z_G=!vCLe|Y000000000000000000000000000000000000N}UI-r8yPk*k+ACTnY>
z(dt>XTS}$D;`vQY!^6XK`}3pOTrNE~U+8Pf3^aCbXzI-tGQIhcrh#nVmQrqKIbSRl
zh6b9JjuoU<j}@ermJ3qrhXzt>(|wt~LVj*Km&=ak`{$NBu6iy~mE5}jv0I)VX}$cC
z($?a(ONZAi?yjqk<RgvAWNqa6W^&Xy96CzR*dVcMyB4=+HgB9)>d237+m@`41TQ?u
zU?IOX(_Jba7_Du=+~#!43k~+@sxy|YS<$(0Rd(aLt&4{*sI8Bzi$rR}!D=J3l9hj$
z{`~U4|GwzlGmH5`X;I6(GyBsc>odinT&cLIrFr<g{L+r)E4vz(G;Z2^OwEkQ-kpaw
z@6G3WGKEEp*Q{Bws(t;64PC1`R(GB`9_?JcblJ*|C0z$fCki&MS+jC+`}#At4`m8F
zH<oA6GCqUWsWUh;Gt!+K>dCAND`qocq<g{go(&5(t?itD+2w83^^x{NCsgTX;nZH1
zbdSy-SUI}0b8y|JwN>?z&PZczxWQs!qvzjX>CO3}(qW66h}<yTd~x$|>!$9mm948f
z6ZMg<7u#cZexOvyZXPOS4(m1^xuJR0CEJ#4>AQ00;86N?@%l*ri|uw|Uvv)@OZoon
z=;6J`A~!6)WX;wcmoHe?H(DxO7ORhRS9(vr_};f<a)XC;9J!&ZeRxUh#?kin?C91_
z(fUZX(r@Hfm~|#xlyvS0U0*zZc<Ayg7GxJMSi7!1d_Kg3dn3XB3;rcc0000000000
z00000000000000000000000000002sH`#IVnn*NS9j%Q`i&Q1I?tko-r>l;Q)kKoz
zSlw7Cc5T%$(V9qYv^rUvtb`t2bw+);^`4h__5c6?0000000000000000000000000
z0000000000@Di&lANIV&lK=n!00000000000000000000000000000000000fR|W(
z_=yIOM#BFA00000000000000000000000000000000000007{3!ST`R$g5(tk^cN>
zHkV7!%@_J2H`Ij%(cmYM@P7aR000000000000000000000000000000000000QlW8
zBmSyne||KZ%cbY$3w`xrXy!G47YY73cz1AB(7gMnyZ>(YHM?KEJG$%hyZ(6BYj?f!
znjeP600000000000000000000000000000000000006+Rv2$ilk3=KUXn0y(Ju4oI
zMXHip_dmF3`9!+u+?Jl!EBlvU+}3g4{29|D$!IkBs!HYB*!oO&W}uYXnC>f%RX^|c
zvGl^ubg_MKYe#1E%GT9wi|Q-QYTGK!YQ~%8cBU5R^V|B<g>9Lhv1aGa8cP@6zj~x=
z{?<#^u5G<+pyS->W6ft(npekH<%^}%W!Yl3G|{fLFqY15?Oivtq+|Qi*3QjWcC<~a
zw2S^;rCn7`ynS<isFdm)pX<wKj-@AV-&kl}*txQ2aCtVfctPD*qp`sfHL*)FrPQ*4
z9r@gjiP4T-IF=s&{!N2zncmLs9ShbhSaCseY;Bsx7P98zp<*fDpB>GlmSzi?-u%c|
zqv?M?md>2N{@lw3ms~z_X{L4gk_&6cF0rN3I979MCO4Q$5A>uq4wdqSY&thS=fwEX
zwLfayux|5??D9fxOR;!<&DeK%&RFYMxI&eGmwxKVvB<=A@7S?&{_0F=)xf~QwuRN<
z$jNAOtZh8J+ER9)FSVhRE=(-%*Pi|ASj)&??r6Mp!@!Ex)=fh@mtR;_9yJ*qpL4u(
zpqMYWIq<EH&H27t-!az9;|qrddb7DqPgmL8#8~SS#^-!s4^7k$(^44g8h3uYQh$7T
zV+Y1aZOrF$o706UZNm*w8Vgt2E{Ijy*3Le(?W)Yc(A0*DmiLFTi9u&a%MEL5>&F@%
zI=@0bUz(^IR*6&v_eO%B2ag611rLO$00000000000000000000000000000000000
z0002+n`&BB{1wrmf!=H`(^FNOh@TKGrTdDBY4I>z%I9;N(}j3#EDZN&28LqEX#Aw)
zU@qOADb|IJtAhI?!IQz`!NbAV!&3kN00000000000000000000000000000000000
z0QikIE&ht=&_HiCm+7f0pO^Ca+~#y4UK>9lT1xj76Uq2V$-!K@J5wx&`ZEJVvHEhu
zJumUZ0RR910000000000000000000000000000000002sC018H?0JbN0RR9100000
z000000000000000000000000000000FR}XaVb4oE2><{900000000000000000000
z000000000000000c!|}ApQ`P5M0Q;<`q7cvp{v4E0000000000000000000000000
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
zOZ&8W%06wePwmtH=6!nW1zoN4a_z%gE*<IFab<aDRqg(GB=~F)1h3xxY<LO)00000
z0000000000000000000000000000000KjjCWr@8fM7NYmgT?ckn)>sj`9j~^?w*0U
z;b}IPOV1t1l$!c8J=t_qw!g2bH(SW`=0}=((>t==`GL9N;iA^&mbS*`g;lRf?2T7?
z3OgDe9zM`R*ke;`bMySB{&Y{KacHn{ym3=oW6Qjj1q<4mo7<XO=gm+2${n;$>0n;`
zSMH!?N(XJRi^2|)ze)$qQ#xp=4;M5R+!G1D9UcGx0000000000000000000000000
z00000000000N^)RLo6Pdzc!cd&J>$A^rs7@#rgcUFx_@qG#**Dc|5bWkRQwxO4+bd
zPo~&i$PSjW`GLByeJuEgNbqmr0RR9100000000000000000000000000000000000
zev_RRUzXgQ&u{Bb7q+b}<Oef_QZ`d;>d6$l3)#U^Ha~D;e13FoF5MkQH-xoHi^prn
z>dWo-yu|Yd00000000000000000000000000000000000004lOSbg|O1a*<%?ZK8{
zes}@^000000000000000000000000000000000000Ko6K*@<b9Xf$$KZ8Tb4JtMY0
z)14V8ZA|wS6Y)q@a_jyFFHDT5)h+Q#)s{-t`tho{os0ANZT;!OwoK1NlZCs+)8O}G
zl_syMG?^Y-l`obq%NDbxgLUV9dp!N_*68#|G#S}DRyp3@)05gf-gPlm%BM<Ovc*(y
zKG%~el(WT5CJbfzQ$5+@U@pBg)04^%lq0Fd2U=~+=X0CWh4Hbz_T=A;rys8muRIa7
zM1uQ*w*^;)CjbBd00000000000000000000000000000000000@M1J35@%h|(4Qae
z+MLgC>rWT96{lpnvZYLacAzISGCvjm*A!2jb<y)xA50fA1Eui>ZK;;?Vu`ahyiotS
zbg|T*@5%ONGd%~#YK<n&T6X;NH0>M8_H+#mWVa7x##^=2g_krf_*^7-CU`RVY4CXP
zNbrN;q2TMmKLz)NVE_OC00000000000000000000000000000000000_zhAOk4CGe
zm5+(4@-dz$A7k-EJQ<B8;*n@w`H(ChYRiY3@}W8&k0k5D*3*LJk>EdrUj#o1z8!o%
z_;~Q1;QF8xbcJC600000000000000000000000000000000000008(Ey)51s?JMNx
zrgORMXuf~$@bK{5X-5jy9VwVRQn2bs!Nie*@goIe$HyC!hc%B!qP68iP5Dq=7tVZI
z@Wn{*Oz>pz)8O&ok>CfxL%}zK2ZDbL!vFvP000000000000000000000000000000
z00000@Eax(Pe!Me4|U~3G7+zh)|L-7<wJG(P*px8%7=LQ5R1oalXYRsX~7+l;FrPA
zgC7Tv20skG6MQ51r{GJ$Jz*FC00000000000000000000000000000000000004gd
zRmWq|$PHCvNn$LCk0r6Hcq|!~#iP-ly2>$`h}TAI%ZHlsp}HJ=ZdzT~&9vZSk>Hu&
z$>68K<G~}r4}yn+Zv^)RcZOjA00000000000000000000000000000000000008(k
zH9cM(jZ`JK?tko-r>7mv#ICJ7ka={~8OcOE60I#CYRZS|@}a7HNR$up@*x(FN0N16
zkMZDvNbu9(2VnvL00000000000000000000000000000000000006%=W+bB3(P@#Y
z<ktO<-STw2lC2xd#;%RkhuLJZl6`d58FgX(c<_@*@J#Szm;e9(000000000000000
z00000000000000000000!0(2tcr+S|C*sNQ7_Uv%g`s%x%}DSc!M}wG0000000000
z00000000000000000000000000002|mYE)}jz+4ITlYV9%hU0Lnb@_lY4Pf0CG+U2
zGwQ;cGlO?Uf?ozd3myx87(5g_7~CIxF}ORpJ@{ns*TDyZo5NxN000000000000000
z00000000000000000000004MtR41azXzh$jQd3_^s;5_ys%e!ZQCCUg$x0Hdtx6=r
zD%FWdG#Z~-Nn$l)N!3`A7)#<~NvtYNlCipQsF}f^MuPtgejYp#JQ92__-63c;7h^X
z!R^5(gTD?w5Zn|N0{{R30000000000000000000000000000000002MOQ9wajYezY
z)5g+RU3DUwjMgN>q&8YpTgk<%E4ldeN}X7|W-N`(tdz!PR7zv@)rn*@8n3D(u|!oO
z8MX|MVNoJcTbry42b&q39SMFG{4jVh_(E`7@ZsR5;BCRapcwQ7ox##zL0Aj`00000
z000000000000000000000000000000000#;64B~tZKNu>b^n7GcFw3|YsRt*@2{_9
ztH-kQTc=mDRb$x`w@<5N6Jy!q-(OeB#>cWV=O-)K*jTpqN452dWOZ~b7x~NT`b1<R
zw`lpyDY@9BTx%gdDfjZ3H3xHFdwgNl!Q6efz9TU`%q1ssb>X#5+jVm!crf^2FdQrn
zj@$jU-8b*vyz5_g-5Z7h00000000000000000000000000000000000004e%oEcvi
z9n7V>Gv}9f4rUgeduB0TC@pH4cV>TjWPPSMlq(e%wKUhB5^o=`Rw-XNwYd7~#NM6b
z<-Pe_Po}VF@tQR&R<*BRv7u{K$Lh{A$D^IAmo8h`v83xj=|sWCHEUKbZeM@q_MuE+
z=f?6(TE=J6I(4WsGb7!(p`OgTuwph7MrsztgXor0X|Q;HQ`7M9@ZA3VXf~Hi&&?P5
zng$E`t(oppv8gv($n@q%n%Wl3ZBDn8v&B+jXrL)MKb}8o>xo7K*}g5M+|Glo>Mn?1
zebiQ&fyT}aM{hf=Dc=1e+iuC^2Ag8@;{7kOe)mwZl<&`uW}4zH@oe%%Hp&c?3h7)^
zW4!AHhUw0SHM5(CN|~m_+40U7sGZ)NA1XCf)rEU(TCg+{JP|w;d?mOe_)zfY!CQiz
z!It3iFbn_y000000000000000000000000000000000000KbA`;<KV7t(RX?+FIOp
z>F}Dx)5?M2^YTkOmapt;T++Cywi0N*xOupBQ+L<O)>T#IK=*>>JsTEoTH87Qvde4A
zfv&~vnavyLl{)gH+v+NT_TeS18%NvQv!h#M<-oEvD>@gh%5Ge@b@6br99YslI)7m0
z=+4f;b(^YZ#%Cojo<BTv`4tPYix;e2SFW)5k~Ld*T)tpk-)N~2F9(`eU9xS-mcA=@
z4i2Rgb>Zx12C+!+MDS4X<>2<<uYx}dt`A0nzTom;X)r%HBRD=R1^@s60000000000
z000000000000000000000002sx85=FS<xLkR?c6YDXkh9SlCum2{c~1VPHjT>!zWd
z%d5+Qp@H6PF4NOhR#gs^^7-86bfFT6R|4t2V%NCD%=oNiA)hZz1j-fqGXp~t`B*v7
zyKZPn$M&VIotv-hm|hN~i|vD3J2InJwytiQQ4VYxY|Hd^cJElQX2FWOO5og<p4Kb-
zmtWl0ao)^wU}K?mVdu)8!R6V^;%Vi;`g1QETypuyrJ2^{OOoZl>XEMbTQ6O^w)L`s
zj{0(-al^XJJF?3Qxh=(FZC!Z@_PoSj0RR91000000000000000000000000000000
z00000yu|9lPa^n!B=}|U)8I$p2><{900000000000000000000000000000000000
d{8p+-M5ECeu|y@UkHstL^jNGa5ltrJ{~s!yL7M;o
new file mode 100644
index 0000000000000000000000000000000000000000..b43dc2389e4a17471bc01ae421f9521fbc2a0afa
GIT binary patch
literal 1179648
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
z-;)oE0RR91000000000000000000000000000000007_*&VkzchRD^+o07G)(P;Io
z+HIxMVDbFs=HcPtdHwm_*<3C?FJI_u&I~kd+R)saEo6H0yP5~GecMX8k#fFRDhv%Y
zFCDE&tsbpNEiG51)(;J&)~5S1eTDqIbS{_Oo$sGl?zrmdNL8}$rYE+2;EI+VJJzng
zw7=N9xTU+UA(D?YC6l$0XPU_|=WygGJ)?sp?rmGJB75oL-3vGDYVF^iY={KUKFDAp
ze^sWtR6I0V+roJ*>DFf(>^C>xvTkwqs?A$=^=@B#Y10L@4Uu(`NNqS+ZDdxm@`vfq
zFaQ1b3m42T<_o0@ThE={pWd}TQyj{biWj!F6m~A@TsH8^-779#*mmH!n(2`PBS(h!
z=5sxn!i9_1tXZ+DWBrN^U8_1*Z<;+;x@q;&<tsavbRDW4uh_U|&C10c>u2v6$`nR6
zmS@m9HiP+-XD~ant2;N;lUWxw%x1!p&FgXtI@)txP2Jg*ZPg8tjw2^j>1NU7Ub5}!
z)hjQX-<Q9<ziDk%Lu6B=sW#kTu`uYFH&}XWeyDWR;wB>3wQnD3U6fruxTAl=(56H~
zr0co%*qt9J6|!50N|~d&jYqEAJ<{DVxU7H4s{SP%uZ}lF`k!mJ<NKm}s94JPXLldn
zdn|HY$J)V-UGsPE=-t+y-5hI(bXR&$KKI_YWpaZ@bsV`a-L-Z>=eof)T^${lT^?<S
zWGnqfev4UW!bM5vrs#U8qqK0_d0m$cHeH%+2;UF!;O<E9e}jJu6951J0000000000
z0000000000000000000000000_<eRlye1NjR!3`N^^vM%-%U?!`#{z4v6@J-Tvj()
zl(@I*xM)qJHd>vmO;(D2bMq|?<>>v-^Xvft000000000000000000000000000000
z000000N{C6S3c~2o+kkS00000000000000000000000000000000000007UkhVUmE
zJQ4~20RR910000000000000000000000000000000002MAA=L4)sZt}wUPe(?rbiX
zo|iB5MXsw0E26<qBH=#(00000000000000000000000000000000000008*oF+F}}
zvOm8&o6Du=<qLfcVbP2|ACClI3EmN08MN&C>AsKe+q3T#`=WdA+52aEU$yted%ho5
z0{{R30000000000000000000000000000000002L!_Jv8EfS4Hqv2_F^{jX-7O6`1
z-So)ik@2)^=k6_Qmld*0bBogL)2Bs}(P;9_O5@tt`b>9bpp@E}?kkQq-*obL*x-_u
zog1$j99*!u&~#x#C9Jls5>_)7mK#Ye&gZxHrwiLNJ)>dkTE@HSTDoCbI^R~<(Z6xS
zf@!1Svnt`$@m2X^DYZFU%$AOfTi3E=Wq$GMeEZ;4JJ&C3tFOdGUs8#ys)=`O%@37Q
zo5tqa{=jH@-e-od$aQWg?H<^&WMgJw-DuG0V2PU8vP>zpd|+ojw{v{7)*p{|uyA3z
zZ)<Mls?zdw>jlZtwP_w*$eK%riluyic6TPVG+W5@=68(-&8r>nq<=@t;PTwi&?OtT
zr(a$>dWo%-;8@M2ncQG1J<yZdI8@3PvgzE|oM$f@O<$I3>s)hQX3L^=%ezL}&aWB0
zhv$q&$HEn={9XFVBag?nKajqvZP8F^XXoba?LCXC!;zEG<Y;U>yxLNBpf9zdlr9`v
z-qW^?rf00p6!XKYO2sR-Eh=t#c~yDTWOQuK@l6B8d^zUOT^*hC58Cb<jh=qb&_HiC
zm+9#$o0k}kK51;uhxX8T`!FqqWnE*=k5}4{EpP157^#i<d~R#HFnO$XEv3=oO6<Z|
zCAN0Xk+G{X14EMoFOT$xW#fa+iIxLvYa2!bkDOm2pD&F!4Vy%&g1aNZ&x1#T2ZQ^=
zQvd(}00000000000000000000000000000000000_<dDh6@O85XrMQn%k)&$CgLYW
zOX<F1qCOrLm-6}C)^s6W8w-p3GXq1hWHf$Caxj<f&J^py;Huz@k>HoXqrpSL1K}wE
z00000000000000000000000000000000000008`6tB=1ZIyBIm&1HJ3%IBqgKDRYp
zh}XtXik8xS#Y8fGN^&rl?#>j;Mg5t9p;$vXaR2i>aR2}S00000000000000000000
z000000000000000c%Idj5Bs0zNdN!<00000000000000000000000000000000000
z!1Ju3eAxdyPXYh{000000000000000000000000000000000000G?+J;ZN0$Pet}_
z+5O>NwL@2irvLx|0000000000000000000000000000000Dm~%n5s%f4xDt|uG6b$
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
z1)YVhL)$ZJF5j5h)?MCNRr@{?2|g19!7KJX8J+?F0000000000000000000000000
z00000000000Py=^dE&rH(QT#DVDbFs=KlQde4%e%chA7Q@HCstrRNP~O3nS5o@}}~
z+uzsRn=NE|^ShdR(>t@>`GI-i;iCC1t!+&$i>fY89EewX3OgDe9zN7V*kkkjmX`MB
z{&Y{KX=t!%EV#L?srB5}g$rBT7tU{KKkvN6Z{5NCNgXVT|JEI}PU>J`?4q!P<ZshK
z%cKq#G=vKp3+{>p-wY1`00000000000000000000000000000000000008iNtT7gk
zw6D#jyEDb+4gKjtX>mTkJxsUHjK(9&w~l4j7V?9cLMa<I>d6$l3)#U^Ha}1o#>awx
zj08Un4*&oF00000000000000000000000000000000000@cV3Le0g$fKEJ&`UD&?1
zkRQwxO4&@YxhGTXE@THw+5EuC@%HH2T)I0f-4M1aEgowfYbeL>f1c+L0000000000
z00000000000000000000000000002bvxe{|5!6M3w+7pS_V5G%000000000000000
z000000000000000000000DwPoa}xEDXf!gjHX5z2o*rAD>COz4Hm3WEiFl+c*>}?;
zTRuLPezG-QY1&$8+A!8MH?laN-`<}tY|r$JhipD`ES>eTSS94lO31X>s(i7uIa|z@
z4!7O#_ObM@uZm8KM3a#NqmAPoJw2(dV_g?hrF^QiEn7_W=5sxnLOEN^WWu6Mf2t>2
z9L%LhGCisMK)EEf_)yfwd_K1|T^JwhCCRb0z9GEw6ZbSnf=>r;3RVZF@B7KV&+L2a
zzU})i*?02Z@9q8Dy@kC?_RiSz<vs7(vm<N<000000000000000000000000000000
z000000010z@rjAH%TMgj@9sME7s<N{`FyEZ+>y(cGF|DRQa(G-liAfZMVqeH_EhV<
z6B1`#aLT0G$xXv<`YT<8t>>raw;Z21>!N3BKbS6L21?@*ZK>Atk4v1j;n_yWrHiHh
zd{4GFo9US_THB1oS<6p)hS<KLY){wFKz7GaW<0EQ?)1dzos~t|mM<P-DJnHxt*zno
z8WPQ`8Y^YlVkuu3*;)QO@WrDFx(0LU?o3a*G&)dtVX4-(X^G}bPJ9lry@h=LcvxHg
za}1g|)||S;%nK?DQJF^Z@L5-HdS|vfKQMavt*QC5lZlz_Q#UPN^?17lXVoTVE}Xhu
zWdhy#p@CAl;mc|gGcP>G*o91YW}tgyywkSk>cq@tQ@1VO;!4MduB#j{w<<BSW9opR
zLT=Kn4HvvAk(hbO)UA)&3FUhmPn@%^a&OCftk{(v7|0io$X3qNrBWfgb!co}=a%p7
z{8(bvipp&oTi~fT(s*U%VY)av{y3Jq?mE=#)S*YT>1v&yYOM<&>iXcbk>H8om%&ei
zM}voh?*$JA4+Q@bd@(Er00000000000000000000000000000000000004mBBUSNe
zw5q;*OjMPR@kIF;iznjAXe<$rMC;0jWcg5AKGc*C)$w>FSr<mv2bV>H-vqx1eiD2$
zxF`5X@Xp}cpcHh4#Q*>R00000000000000000000000000000000000@LPI8yeZmO
z$j?jXa@pPa{&~a0!}IE=Dy*BTFgaCW)l`LvsS4v$6~<1CHzkh>k4K`l<wH&RP+b?!
zygvARBzPkDW$@GB(ct0Wd%=Uj*Mj?le+r8M000000000000000000000000000000
z00000007|kOd_6))|U@;<wG(NuZ`B04>jdOb@@<LJ|xPAc=-^E$7_>yVPt*qsYvka
z;OD`QgGYkz2j2?57W_-_h2XBR7ytkO00000000000000000000000000000000000
ze)m<!W6{WURijB_G>MNUv8s418P>(4(Vn`>F`0<hMr+H5n)0E#T=;Z-UD!>1@b{76
ziQt#PPlHE;hlB404+dWgz8Ksd76SkP00000000000000000000000000000000000
z!0)JO@#<)#D%p3_6Wcyee>ju4x9(8pH#gssOvEG6+VY{Me5fuTs>+8%`4BH3V)1w+
zSr_&g5AKfyKMlSYCIA2c00000000000000000000000000000000000@CRdhB3d1-
zk5nc5ZhB(d2jZ1%-Doy(Z>%BACX<!yZ*IP&E^HqUei8|u2!0tR000000000000000
z000000000000000000000002+$Dt}7jmF}McrrZ3Ym;?hQ9Ss1B>2zZhhYK$00000
z000000000000000000000000000000004hrrp2qHk*Z|hO;2q5K>Tnfac`_XUY)FD
zesl9Jbz#dH!P_IjuY;cj{}FsYcrf^Ca9{BG;LhN-;A6qx2JZ`Q466YE0000000000
z00000000000000000000000000O0vioror*wbLs}O+zKAo>ob!>MKd2u9C!)l_XYM
zl}Lt7suPiDG(Mw}#A-&9s?j7dn#4zwSXG!LV|C$BGlIX21iuM>9y}I29DFDEdhq4o
z3&EYiZNbNazYX3O+z?g+00000000000000000000000000000000000006-Ap(YWH
zMr-2rqiL+JIuT7qYm#A78?C9W<l@zpTzp!kO)OqBn#N{SYGczYwXufkL^2wUS5=Z&
zqAHOLBg11@l}OaqChNk%W&~$Pf}aK7555|FF1R(gCAcAYOK>nK20g*1U}>;0tOfu8
z00000000000000000000000000000000000fQspfXmzwUQkCqx>5<DL(<|AU(d?#^
z8!FlA(d@dGX_ai%X!g9%)K{{J(QNwzb(L&<G~4>)WF;FL&Au#E+mJ|BM@MsKtgUWH
zM8<QMM`ldQ#U|v|wZtdn+8?Nykehx_)#2O^+U`qC3v<cwTwQo=^?PrO1YZqq3WkHl
z!3q2Rb>EHqw(kAG-n+wM00000000000000000000000000000000000004mB8MEW-
zqJz0~cjo-k$YAEe1+$C!Lg~WRb7%LbcdgG9hjOLjg{>{Mr^P$QnpNr-O|GuKI&olR
ztiCs&>&X-@T)bw@id7x!S8V87)wz1p?6J~KtCucc*}0_aQ0;id#x-kJF78-Ad&f|w
zFtV{clh(1B%%42e?98t2+)z(uUDz<22}^1&j0e$erP5&W{O0E2;o*7x`Q6!EE<G<_
z=xZJ<<gdzfmx|53*+Ql_zpJ@z;k=e~YdKpi6@~_ylkM^RF{8(W2C{wIO1Y84QFRx@
zuRdl}W}s=)hGWOpH^;l5W9+s}Zm>CaZoL0Fw(lM)mh%1C-I?ZiYdo8LjzO7$QX!pd
zZi;t3%P`&fuw{1ZP$|=#I6J=SSz4#J=7&nnRdwMWs}Gh&g2#dfgD(ZQ1vdwO6<iza
z3i^UqhQ$B?000000000000000000000000000000000000PtHlE<P)|d!)N#a9RJ7
zRsBmk5;Nknl0zM(h1<^Sx@@rN(rmdwVds+0WdpC=z2ee^ZMEfsY<qh3%FE{W<uC7V
zsxB9#yVfq~TsOF;tE1zxSh?VemK{6RuD-Ot*t@u;zFe?*U2Z`~d#<agJG-)`T(E9&
z_NvWWcJ*#wduda$T+p$0aAVi}-8*`>wP)kyg7)nrt&6hD2Y2*u7^*54v@KYXy>#*J
zg&TIY_Se;gv!4;fBEe(9gTa@A+k%^ezY4Amb_IRG=3r^i9=tR-F{}mv0000000000
z00000000000000000000000000N@Yaaq(Hv;VW{T8%nzewk+A0sV^4{4fJMnnVzn)
zs&YXopU-Vg7b*quN<q4>*fl0GBR(rx$mdJr1?2{VOImhrylQZ8!RA8K^m0M}j+VjY
zxuKy;Hf&EPD+QT>q49`Vxgb-_53ec}uh_PzxTU&WkiM#I(NJk;=jQG0JvHTmuARHL
ztX)>fF3l}U&!`kE-LNd3Z!7HR-?*WnT(D$ie(~yj``}eO*Dsq^E?BrQ-M2Nja#d-0
zy0xxc(AK%;yv&wG>y~$owAI#?mtg<%d<y^o000000000000000000000000000000
z000000N{C67ycxI??!@O2R{vd6rKP800000000000000000000000000000000000
f0KgxlnnW}jogPb6(uP>Pl1_`osuIy;GXDPnRw!H!
new file mode 100644
--- /dev/null
+++ b/toolkit/components/places/tests/migration/test_current_from_v25.js
@@ -0,0 +1,30 @@
+/* Any copyright is dedicated to the Public Domain.
+   http://creativecommons.org/publicdomain/zero/1.0/ */
+
+add_task(function* setup() {
+  yield setupPlacesDatabase("places_v25.sqlite");
+});
+
+add_task(function* database_is_valid() {
+  Assert.equal(PlacesUtils.history.databaseStatus,
+               PlacesUtils.history.DATABASE_STATUS_UPGRADED);
+
+  let db = yield PlacesUtils.promiseDBConnection();
+  Assert.equal((yield db.getSchemaVersion()), CURRENT_SCHEMA_VERSION);
+});
+
+add_task(function* test_dates_rounded() {
+  let root = yield PlacesUtils.promiseBookmarksTree();
+  function ensureDates(node) {
+    // When/if promiseBookmarksTree returns these as Date objects, switch this
+    // test to use getItemDateAdded and getItemLastModified.  And when these
+    // methods are removed, this test can be eliminated altogether.
+    Assert.strictEqual(typeof(node.dateAdded), "number");
+    Assert.strictEqual(typeof(node.lastModified), "number");
+    Assert.strictEqual(node.dateAdded % 1000, 0);
+    Assert.strictEqual(node.lastModified % 1000, 0);
+    if ("children" in node)
+      node.children.forEach(ensureDates);
+  }
+  ensureDates(root);
+});
--- a/toolkit/components/places/tests/migration/xpcshell.ini
+++ b/toolkit/components/places/tests/migration/xpcshell.ini
@@ -9,14 +9,16 @@ support-files =
   places_v16.sqlite
   places_v17.sqlite
   places_v19.sqlite
   places_v21.sqlite
   places_v22.sqlite
   places_v23.sqlite
   places_v24.sqlite
   places_v25.sqlite
+  places_v26.sqlite
 
 [test_current_from_downgraded.js]
 [test_current_from_v6.js]
 [test_current_from_v16.js]
 [test_current_from_v19.js]
 [test_current_from_v24.js]
+[test_current_from_v25.js]
--- a/toolkit/components/places/tests/queries/test_sorting.js
+++ b/toolkit/components/places/tests/queries/test_sorting.js
@@ -275,34 +275,34 @@ tests.push({
         parentFolder: PlacesUtils.bookmarks.toolbarFolder,
         index: 2,
         title: "z",
         isInQuery: true },
 
       // if URIs are equal, should fall back to date
       { isBookmark: true,
         isDetails: true,
-        lastVisit: timeInMicroseconds + 1,
+        lastVisit: timeInMicroseconds + 1000,
         uri: "http://example.com/c",
         parentFolder: PlacesUtils.bookmarks.toolbarFolder,
         index: 3,
         title: "x",
         isInQuery: true },
 
       // if no URI (e.g., node is a folder), should fall back to title
       { isFolder: true,
         parentFolder: PlacesUtils.bookmarks.toolbarFolder,
         index: 4,
         title: "a",
         isInQuery: true },
 
       // if URIs and dates are equal, should fall back to bookmark index
       { isBookmark: true,
         isDetails: true,
-        lastVisit: timeInMicroseconds + 1,
+        lastVisit: timeInMicroseconds + 1000,
         uri: "http://example.com/c",
         parentFolder: PlacesUtils.bookmarks.toolbarFolder,
         index: 5,
         title: "x",
         isInQuery: true },
 
       // if no URI and titles are equal, should fall back to bookmark index
       { isFolder: true,
@@ -382,26 +382,26 @@ tests.push({
         title: "y1",
         parentFolder: PlacesUtils.bookmarks.toolbarFolder,
         index: 2,
         isInQuery: true },
 
       // if visitCounts are equal, should fall back to date
       { isBookmark: true,
         uri: "http://example.com/b2",
-        lastVisit: timeInMicroseconds + 1,
+        lastVisit: timeInMicroseconds + 1000,
         title: "y2a",
         parentFolder: PlacesUtils.bookmarks.toolbarFolder,
         index: 3,
         isInQuery: true },
 
       // if visitCounts and dates are equal, should fall back to bookmark index
       { isBookmark: true,
         uri: "http://example.com/b2",
-        lastVisit: timeInMicroseconds + 1,
+        lastVisit: timeInMicroseconds + 1000,
         title: "y2b",
         parentFolder: PlacesUtils.bookmarks.toolbarFolder,
         index: 4,
         isInQuery: true },
     ];
 
     this._sortedData = [
       this._unsortedData[0],
@@ -413,18 +413,18 @@ tests.push({
 
     // This function in head_queries.js creates our database with the above data
     yield task_populateDB(this._unsortedData);
     // add visits to increase visit count
     yield promiseAddVisits([
       { uri: uri("http://example.com/a"), transition: TRANSITION_TYPED, visitDate: timeInMicroseconds },
       { uri: uri("http://example.com/b1"), transition: TRANSITION_TYPED, visitDate: timeInMicroseconds },
       { uri: uri("http://example.com/b1"), transition: TRANSITION_TYPED, visitDate: timeInMicroseconds },
-      { uri: uri("http://example.com/b2"), transition: TRANSITION_TYPED, visitDate: timeInMicroseconds + 1 },
-      { uri: uri("http://example.com/b2"), transition: TRANSITION_TYPED, visitDate: timeInMicroseconds + 1 },
+      { uri: uri("http://example.com/b2"), transition: TRANSITION_TYPED, visitDate: timeInMicroseconds + 1000 },
+      { uri: uri("http://example.com/b2"), transition: TRANSITION_TYPED, visitDate: timeInMicroseconds + 1000 },
       { uri: uri("http://example.com/c"), transition: TRANSITION_TYPED, visitDate: timeInMicroseconds },
       { uri: uri("http://example.com/c"), transition: TRANSITION_TYPED, visitDate: timeInMicroseconds },
       { uri: uri("http://example.com/c"), transition: TRANSITION_TYPED, visitDate: timeInMicroseconds },
     ]);
   },
 
   check: function() {
     // Query
@@ -560,51 +560,51 @@ tests.push({
 
     var timeInMicroseconds = Date.now() * 1000;
     this._unsortedData = [
       { isBookmark: true,
         uri: "http://example.com/b1",
         parentFolder: PlacesUtils.bookmarks.toolbarFolder,
         index: 0,
         title: "y1",
-        dateAdded: timeInMicroseconds -1,
+        dateAdded: timeInMicroseconds - 1000,
         isInQuery: true },
 
       { isBookmark: true,
         uri: "http://example.com/a",
         parentFolder: PlacesUtils.bookmarks.toolbarFolder,
         index: 1,
         title: "z",
-        dateAdded: timeInMicroseconds - 2,
+        dateAdded: timeInMicroseconds - 2000,
         isInQuery: true },
 
       { isBookmark: true,
         uri: "http://example.com/c",
         parentFolder: PlacesUtils.bookmarks.toolbarFolder,
         index: 2,
         title: "x",
         dateAdded: timeInMicroseconds,
         isInQuery: true },
 
       // if dateAddeds are equal, should fall back to title
       { isBookmark: true,
         uri: "http://example.com/b2",
         parentFolder: PlacesUtils.bookmarks.toolbarFolder,
         index: 3,
         title: "y2",
-        dateAdded: timeInMicroseconds - 1,
+        dateAdded: timeInMicroseconds - 1000,
         isInQuery: true },
 
       // if dateAddeds and titles are equal, should fall back to bookmark index
       { isBookmark: true,
         uri: "http://example.com/b3",
         parentFolder: PlacesUtils.bookmarks.toolbarFolder,
         index: 4,
         title: "y3",
-        dateAdded: timeInMicroseconds - 1,
+        dateAdded: timeInMicroseconds - 1000,
         isInQuery: true },
     ];
 
     this._sortedData = [
       this._unsortedData[1],
       this._unsortedData[0],
       this._unsortedData[3],
       this._unsortedData[4],
@@ -650,52 +650,52 @@ tests.push({
 
     var timeInMicroseconds = Date.now() * 1000;
     this._unsortedData = [
       { isBookmark: true,
         uri: "http://example.com/b1",
         parentFolder: PlacesUtils.bookmarks.toolbarFolder,
         index: 0,
         title: "y1",
-        lastModified: timeInMicroseconds -1,
+        lastModified: timeInMicroseconds - 1000,
         isInQuery: true },
 
       { isBookmark: true,
         uri: "http://example.com/a",
         parentFolder: PlacesUtils.bookmarks.toolbarFolder,
         index: 1,
         title: "z",
-        lastModified: timeInMicroseconds - 2,
+        lastModified: timeInMicroseconds - 2000,
         isInQuery: true },
 
       { isBookmark: true,
         uri: "http://example.com/c",
         parentFolder: PlacesUtils.bookmarks.toolbarFolder,
         index: 2,
         title: "x",
         lastModified: timeInMicroseconds,
         isInQuery: true },
 
       // if lastModifieds are equal, should fall back to title
       { isBookmark: true,
         uri: "http://example.com/b2",
         parentFolder: PlacesUtils.bookmarks.toolbarFolder,
         index: 3,
         title: "y2",
-        lastModified: timeInMicroseconds - 1,
+        lastModified: timeInMicroseconds - 1000,
         isInQuery: true },
 
       // if lastModifieds and titles are equal, should fall back to bookmark
       // index
       { isBookmark: true,
         uri: "http://example.com/b3",
         parentFolder: PlacesUtils.bookmarks.toolbarFolder,
         index: 4,
         title: "y3",
-        lastModified: timeInMicroseconds - 1,
+        lastModified: timeInMicroseconds - 1000,
         isInQuery: true },
     ];
 
     this._sortedData = [
       this._unsortedData[1],
       this._unsortedData[0],
       this._unsortedData[3],
       this._unsortedData[4],
@@ -1269,9 +1269,9 @@ add_task(function test_sorting()
     yield promiseAsyncUpdates();
     test.check();
     // sorting reversed, usually SORT_BY have ASC and DESC
     test.check_reverse();
     // Execute cleanup tasks
     remove_all_bookmarks();
     yield promiseClearHistory();
   }
-});
\ No newline at end of file
+});
--- a/toolkit/components/places/tests/unit/test_398914.js
+++ b/toolkit/components/places/tests/unit/test_398914.js
@@ -92,17 +92,17 @@ function run_test() {
   // but could be equal if the test runs faster than our PRNow()
   // granularity
   do_check_true(bm1lm >= bm2lm);
 
   // we need to ensure that bm1 last modified date is greater
   // that the modified date of bm2, otherwise in case of a "tie"
   // bm2 will win, as it has a bigger item id
   if (bm1lm == bm2lm) 
-    bmsvc.setItemLastModified(bm1, bm2lm + 1);
+    bmsvc.setItemLastModified(bm1, bm2lm + 1000);
 
   [url, postdata] = PlacesUtils.getURLAndPostDataForKeyword("foo");
   do_check_eq(testURI.spec, url);
   do_check_eq(postdata, "pdata1");
 
   // cleanup
   bmsvc.removeItem(bm1);
   bmsvc.removeItem(bm2);
--- a/toolkit/components/places/tests/unit/test_419731.js
+++ b/toolkit/components/places/tests/unit/test_419731.js
@@ -33,17 +33,17 @@ function run_test() {
   let tagItemId = tagNode.itemId;
   tagRoot.containerOpen = false;
 
   // change bookmark 1 title
   PlacesUtils.bookmarks.setItemTitle(bookmark1id, "new title 1");
 
   // Workaround timers resolution and time skews.
   let bookmark2LastMod = PlacesUtils.bookmarks.getItemLastModified(bookmark2id);
-  PlacesUtils.bookmarks.setItemLastModified(bookmark1id, bookmark2LastMod + 1);
+  PlacesUtils.bookmarks.setItemLastModified(bookmark1id, bookmark2LastMod + 1000);
 
   // Query the tag.
   options = PlacesUtils.history.getNewQueryOptions();
   options.queryType = Ci.nsINavHistoryQueryOptions.QUERY_TYPE_BOOKMARKS;
   options.resultType = options.RESULTS_AS_TAG_QUERY;
 
   query = PlacesUtils.history.getNewQuery();
   result = PlacesUtils.history.executeQuery(query, options);
@@ -71,17 +71,17 @@ function run_test() {
   theTag.containerOpen = false;
   root.containerOpen = false;
 
   // Change bookmark 2 title.
   PlacesUtils.bookmarks.setItemTitle(bookmark2id, "new title 2");
 
   // Workaround timers resolution and time skews.
   let bookmark1LastMod = PlacesUtils.bookmarks.getItemLastModified(bookmark1id);
-  PlacesUtils.bookmarks.setItemLastModified(bookmark2id, bookmark1LastMod + 1);
+  PlacesUtils.bookmarks.setItemLastModified(bookmark2id, bookmark1LastMod + 1000);
 
   // Check that tag container contains new title
   options = PlacesUtils.history.getNewQueryOptions();
   options.queryType = Ci.nsINavHistoryQueryOptions.QUERY_TYPE_BOOKMARKS;
   options.resultType = options.RESULTS_AS_TAG_CONTENTS;
 
   query = PlacesUtils.history.getNewQuery();
   query.setFolders([tagItemId], 1);
--- a/toolkit/components/places/tests/unit/test_lastModified.js
+++ b/toolkit/components/places/tests/unit/test_lastModified.js
@@ -18,17 +18,17 @@ function run_test() {
                                  "itemTitle");
   var dateAdded = bs.getItemDateAdded(itemId);
   do_check_eq(dateAdded, bs.getItemLastModified(itemId));
 
   // Change lastModified, then change dateAdded.  LastModified should be set
   // to the new dateAdded.
   // This could randomly fail on virtual machines due to timing issues, so
   // we manually increase the time value.  See bug 500640 for details.
-  bs.setItemLastModified(itemId, dateAdded + 1);
-  do_check_true(bs.getItemLastModified(itemId) === dateAdded + 1);
+  bs.setItemLastModified(itemId, dateAdded + 1000);
+  do_check_true(bs.getItemLastModified(itemId) === dateAdded + 1000);
   do_check_true(bs.getItemDateAdded(itemId) < bs.getItemLastModified(itemId));
-  bs.setItemDateAdded(itemId, dateAdded + 2);
-  do_check_true(bs.getItemDateAdded(itemId) === dateAdded + 2);
+  bs.setItemDateAdded(itemId, dateAdded + 2000);
+  do_check_true(bs.getItemDateAdded(itemId) === dateAdded + 2000);
   do_check_eq(bs.getItemDateAdded(itemId), bs.getItemLastModified(itemId));
 
   bs.removeItem(itemId);
 }
--- a/toolkit/components/places/tests/unit/test_placesTxn.js
+++ b/toolkit/components/places/tests/unit/test_placesTxn.js
@@ -612,17 +612,17 @@ add_test(function test_generic_item_anno
 });
 
 add_test(function test_editing_item_date_added() {
   let testURI = NetUtil.newURI("http://test_editing_item_date_added.com");
   let testBkmId = bmsvc.insertBookmark(root, testURI, bmsvc.DEFAULT_INDEX,
                                        "Test editing item date added");
 
   let oldAdded = bmsvc.getItemDateAdded(testBkmId);
-  let newAdded = Date.now() + 1000;
+  let newAdded = Date.now() * 1000 + 1000;
   let txn = new PlacesEditItemDateAddedTransaction(testBkmId, newAdded);
 
   txn.doTransaction();
   do_check_eq(newAdded, bmsvc.getItemDateAdded(testBkmId));
 
   txn.undoTransaction();
   do_check_eq(oldAdded, bmsvc.getItemDateAdded(testBkmId));
 
@@ -630,17 +630,17 @@ add_test(function test_editing_item_date
 });
 
 add_test(function test_edit_item_last_modified() {
   let testURI = NetUtil.newURI("http://test_edit_item_last_modified.com");
   let testBkmId = bmsvc.insertBookmark(root, testURI, bmsvc.DEFAULT_INDEX,
                                        "Test editing item last modified");
 
   let oldModified = bmsvc.getItemLastModified(testBkmId);
-  let newModified = Date.now() + 1000;
+  let newModified = Date.now() * 1000 + 1000;
   let txn = new PlacesEditItemLastModifiedTransaction(testBkmId, newModified);
 
   txn.doTransaction();
   do_check_eq(newModified, bmsvc.getItemLastModified(testBkmId));
 
   txn.undoTransaction();
   do_check_eq(oldModified, bmsvc.getItemLastModified(testBkmId));
 
@@ -859,17 +859,17 @@ add_test(function test_aggregate_removeI
 });
 
 add_test(function test_create_item_with_childTxn() {
   let testFolder = bmsvc.createFolder(root, "Test creating an item with childTxns", bmsvc.DEFAULT_INDEX);
 
   const BOOKMARK_TITLE = "parent item";
   let testURI = NetUtil.newURI("http://test_create_item_with_childTxn.com");
   let childTxns = [];
-  let newDateAdded = Date.now() - 20000;
+  let newDateAdded = Date.now() * 1000 - 20000;
   let editDateAdddedTxn = new PlacesEditItemDateAddedTransaction(null, newDateAdded);
   childTxns.push(editDateAdddedTxn);
 
   let itemChildAnnoObj = { name: "testAnno/testInt",
                            type: Ci.nsIAnnotationService.TYPE_INT32,
                            flags: 0,
                            value: 123,
                            expires: Ci.nsIAnnotationService.EXPIRE_NEVER };