diff --git a/trac/attachment.py b/trac/attachment.py
--- a/trac/attachment.py
+++ b/trac/attachment.py
@@ -21,7 +21,6 @@
 import re
 import shutil
 import sys
-import time
 import unicodedata
 
 from genshi.builder import tag
@@ -36,7 +35,8 @@
 from trac.resource import *
 from trac.search import search_to_sql, shorten_result
 from trac.util import get_reporter_id, create_unique_file
-from trac.util.datefmt import format_datetime, to_timestamp, utc
+from trac.util.datefmt import format_datetime, from_utimestamp, \
+                              to_datetime, to_utimestamp, utc
 from trac.util.text import exception_to_unicode, pretty_size, print_table, \
                            unicode_quote, unicode_unquote
 from trac.util.translation import _
@@ -150,8 +150,7 @@
         self.filename = row[0]
         self.description = row[1]
         self.size = row[2] and int(row[2]) or 0
-        time = row[3] and int(row[3]) or 0
-        self.date = datetime.fromtimestamp(time, utc)
+        self.date = from_utimestamp(row[3])
         self.author = row[4]
         self.ipnr = row[5]
 
@@ -199,7 +198,6 @@
 
 
     def insert(self, filename, fileobj, size, t=None, db=None):
-        # FIXME: `t` should probably be switched to `datetime` too
         if not db:
             db = self.env.get_db_cnx()
             handle_ta = True
@@ -207,8 +205,11 @@
             handle_ta = False
 
         self.size = size and int(size) or 0
-        timestamp = int(t or time.time())
-        self.date = datetime.fromtimestamp(timestamp, utc)
+        if t is None:
+            t = datetime.now(utc)
+        elif not isinstance(t, datetime): # Compatibility with 0.11
+            t = to_datetime(t, utc)
+        self.date = t
 
         # Make sure the path to the attachment is inside the environment
         # attachments directory
@@ -232,7 +233,7 @@
             cursor.execute("INSERT INTO attachment "
                            "VALUES (%s,%s,%s,%s,%s,%s,%s,%s)",
                            (self.parent_realm, self.parent_id, filename,
-                            self.size, timestamp, self.description,
+                            self.size, to_utimestamp(t), self.description,
                             self.author, self.ipnr))
             shutil.copyfileobj(fileobj, targetfile)
             self.resource.id = self.filename = filename
@@ -265,8 +266,7 @@
             attachment.filename = filename
             attachment.description = description
             attachment.size = size and int(size) or 0
-            time = time and int(time) or 0
-            attachment.date = datetime.fromtimestamp(time, utc)
+            attachment.date = from_utimestamp(time or 0)
             attachment.author = author
             attachment.ipnr = ipnr
             yield attachment
@@ -452,9 +452,9 @@
                        "  FROM attachment "
                        "  WHERE time > %s AND time < %s "
                        "        AND type = %s",
-                       (to_timestamp(start), to_timestamp(stop), realm))
+                       (to_utimestamp(start), to_utimestamp(stop), realm))
         for realm, id, filename, ts, description, author in cursor:
-            time = datetime.fromtimestamp(ts, utc)
+            time = from_utimestamp(ts)
             yield ('created', realm, id, filename, time, description, author)
 
     def get_timeline_events(self, req, resource_realm, start, stop):
@@ -502,7 +502,7 @@
             if 'ATTACHMENT_VIEW' in req.perm(attachment):
                 yield (get_resource_url(self.env, attachment, req.href),
                        get_resource_shortname(self.env, attachment),
-                       datetime.fromtimestamp(time, utc), author,
+                       from_utimestamp(time), author,
                        shorten_result(desc, terms))
     
     # IResourceManager methods
diff --git a/trac/db/api.py b/trac/db/api.py
--- a/trac/db/api.py
+++ b/trac/db/api.py
@@ -83,12 +83,12 @@
         self._cnx_pool = None
 
     def init_db(self):
-        connector, args = self._get_connector()
+        connector, args = self.get_connector()
         connector.init_db(**args)
 
     def get_connection(self):
         if not self._cnx_pool:
-            connector, args = self._get_connector()
+            connector, args = self.get_connector()
             self._cnx_pool = ConnectionPool(5, connector, **args)
         return self._cnx_pool.get_cnx(self.timeout or None)
 
@@ -104,7 +104,7 @@
         @param dest: base filename to write to.
         Returns the file actually written.
         """
-        connector, args = self._get_connector()
+        connector, args = self.get_connector()
         if not dest:
             backup_dir = self.backup_dir
             if backup_dir[0] != "/":
@@ -120,7 +120,7 @@
             os.makedirs(backup_dir)
         return connector.backup(dest)
 
-    def _get_connector(self): ### FIXME: Make it public?
+    def get_connector(self):
         scheme, args = _parse_db_str(self.connection_uri)
         candidates = [
             (priority, connector)
@@ -147,6 +147,8 @@
             args['log'] = self.log
         return connector, args
 
+    _get_connector = get_connector  # For 0.11 compatibility
+
 
 def _parse_db_str(db_str):
     scheme, rest = db_str.split(':', 1)
diff --git a/trac/db/mysql_backend.py b/trac/db/mysql_backend.py
--- a/trac/db/mysql_backend.py
+++ b/trac/db/mysql_backend.py
@@ -52,6 +52,11 @@
 except ImportError:
     has_mysqldb = False
 
+# Mapping from "abstract" SQL types to DB-specific types
+_type_map = {
+    'int64': 'bigint',
+}
+
 
 class MySQLConnector(Component):
     """Database connector for MySQL version 4.1 and greater.
@@ -134,6 +139,7 @@
         coldefs = []
         for column in table.columns:
             ctype = column.type
+            ctype = _type_map.get(ctype, ctype)
             if column.auto_increment:
                 ctype = 'INT UNSIGNED NOT NULL AUTO_INCREMENT'
                 # Override the column type, as a text field cannot
@@ -152,6 +158,23 @@
                   '_'.join(index.columns), table.name,
                   self._collist(table, index.columns))
 
+    def alter_column_types(self, table, columns):
+        """Yield SQL statements altering the type of one or more columns of
+        a table.
+        
+        Type changes are specified as a `columns` dict mapping column names
+        to `(from, to)` SQL type tuples.
+        """
+        alterations = []
+        for name, (from_, to) in sorted(columns.iteritems()):
+            to = _type_map.get(to, to)
+            if to != _type_map.get(from_, from_):
+                alterations.append((name, to))
+        if alterations:
+            yield "ALTER TABLE %s %s" % (table,
+                ', '.join("MODIFY %s %s" % each
+                          for each in alterations))
+
     def backup(self, dest_file):
         try:
             from subprocess import Popen, PIPE
@@ -204,7 +227,7 @@
         self._is_closed = False
 
     def cast(self, column, type):
-        if type == 'int':
+        if type == 'int'or type == 'int64':
             type = 'signed'
         elif type == 'text':
             type = 'char'
diff --git a/trac/db/postgres_backend.py b/trac/db/postgres_backend.py
--- a/trac/db/postgres_backend.py
+++ b/trac/db/postgres_backend.py
@@ -45,6 +45,11 @@
 
 _like_escape_re = re.compile(r'([/_%])')
 
+# Mapping from "abstract" SQL types to DB-specific types
+_type_map = {
+    'int64': 'bigint',
+}
+
 
 class PostgreSQLConnector(Component):
     """Database connector for PostgreSQL.
@@ -97,9 +102,10 @@
         coldefs = []
         for column in table.columns:
             ctype = column.type
+            ctype = _type_map.get(ctype, ctype)
             if column.auto_increment:
                 ctype = 'SERIAL'
-            if len(table.key) == 1 and column.name in table.key:
+            elif len(table.key) == 1 and column.name in table.key:
                 ctype += ' PRIMARY KEY'
             coldefs.append('    "%s" %s' % (column.name, ctype))
         if len(table.key) > 1:
@@ -114,6 +120,23 @@
                      '_'.join(index.columns), table.name,
                      '","'.join(index.columns))
 
+    def alter_column_types(self, table, columns):
+        """Yield SQL statements altering the type of one or more columns of
+        a table.
+        
+        Type changes are specified as a `columns` dict mapping column names
+        to `(from, to)` SQL type tuples.
+        """
+        alterations = []
+        for name, (from_, to) in sorted(columns.iteritems()):
+            to = _type_map.get(to, to)
+            if to != _type_map.get(from_, from_):
+                alterations.append((name, to))
+        if alterations:
+            yield "ALTER TABLE %s %s" % (table,
+                ', '.join("ALTER COLUMN %s TYPE %s" % each
+                          for each in alterations))
+
     def backup(self, dest_file):
         try:
             from subprocess import Popen, PIPE
@@ -191,7 +214,7 @@
 
     def cast(self, column, type):
         # Temporary hack needed for the union of selects in the search module
-        return 'CAST(%s AS %s)' % (column, type)
+        return 'CAST(%s AS %s)' % (column, _type_map.get(type, type))
 
     def concat(self, *args):
         return '||'.join(args)
diff --git a/trac/db/sqlite_backend.py b/trac/db/sqlite_backend.py
--- a/trac/db/sqlite_backend.py
+++ b/trac/db/sqlite_backend.py
@@ -108,18 +108,23 @@
                     return
                 yield row
 
+# Mapping from "abstract" SQL types to DB-specific types
+_type_map = {
+    'int': 'integer',
+    'int64': 'integer',
+}
+
 
 def _to_sql(table):
     sql = ["CREATE TABLE %s (" % table.name]
     coldefs = []
     for column in table.columns:
         ctype = column.type.lower()
+        ctype = _type_map.get(ctype, ctype)
         if column.auto_increment:
             ctype = "integer PRIMARY KEY"
         elif len(table.key) == 1 and column.name in table.key:
             ctype += " PRIMARY KEY"
-        elif ctype == "int":
-            ctype = "integer"
         coldefs.append("    %s %s" % (column.name, ctype))
     if len(table.key) > 1:
         coldefs.append("    UNIQUE (%s)" % ','.join(table.key))
@@ -182,6 +187,19 @@
     def to_sql(self, table):
         return _to_sql(table)
 
+    def alter_column_types(self, table, columns):
+        """Yield SQL statements altering the type of one or more columns of
+        a table.
+        
+        Type changes are specified as a `columns` dict mapping column names
+        to `(from, to)` SQL type tuples.
+        """
+        for name, (from_, to) in sorted(columns.iteritems()):
+            if _type_map.get(to, to) != _type_map.get(from_, from_):
+                raise NotImplementedError('Conversion from %s to %s is not '
+                                          'implemented' % (from_, to))
+        return ()
+
     def backup(self, dest_file):
         """Simple SQLite-specific backup of the database.
 
@@ -195,6 +213,7 @@
             raise TracError("Backup attempt failed")
         return dest_file
 
+
 class SQLiteConnection(ConnectionWrapper):
     """Connection wrapper for SQLite."""
 
@@ -243,7 +262,7 @@
 
     def cast(self, column, type):
         if sqlite_version >= 30203:
-            return 'CAST(%s AS %s)' % (column, type)
+            return 'CAST(%s AS %s)' % (column, _type_map.get(type, type))
         elif type == 'int':
             # hack to force older SQLite versions to convert column to an int
             return '1*' + column
diff --git a/trac/db/tests/__init__.py b/trac/db/tests/__init__.py
--- a/trac/db/tests/__init__.py
+++ b/trac/db/tests/__init__.py
@@ -1,7 +1,6 @@
 import unittest
 
-from trac.db.tests import api
-from trac.db.tests import postgres_test
+from trac.db.tests import api, mysql_test, postgres_test
 
 from trac.db.tests.functional import functionalSuite
 
@@ -9,6 +8,7 @@
 
     suite = unittest.TestSuite()
     suite.addTest(api.suite())
+    suite.addTest(mysql_test.suite())
     suite.addTest(postgres_test.suite())
     return suite
 
diff --git a/trac/db/tests/mysql_test.py b/trac/db/tests/mysql_test.py
new file mode 100644
--- /dev/null
+++ b/trac/db/tests/mysql_test.py
@@ -0,0 +1,61 @@
+# -*- coding: utf-8 -*-
+#
+# Copyright (C) 2009 Edgewall Software
+# All rights reserved.
+#
+# This software is licensed as described in the file COPYING, which
+# you should have received as part of this distribution. The terms
+# are also available at http://trac.edgewall.org/wiki/TracLicense.
+#
+# This software consists of voluntary contributions made by many
+# individuals. For the exact contribution history, see the revision
+# history and logs, available at http://trac.edgewall.org/log/.
+
+import unittest
+
+from trac.db.mysql_backend import MySQLConnector
+from trac.test import EnvironmentStub
+
+
+class MySQLTableAlterationSQLTest(unittest.TestCase):
+    def setUp(self):
+        self.env = EnvironmentStub()
+    
+    def test_alter_column_types(self):
+        connector = MySQLConnector(self.env)
+        sql = connector.alter_column_types('milestone',
+                                           {'due': ('int', 'int64'),
+                                            'completed': ('int', 'int64')})
+        sql = list(sql)
+        self.assertEqual([
+            "ALTER TABLE milestone "
+                "MODIFY completed bigint, "
+                "MODIFY due bigint",
+            ], sql)
+
+    def test_alter_column_types_same(self):
+        connector = MySQLConnector(self.env)
+        sql = connector.alter_column_types('milestone',
+                                           {'due': ('int', 'int'),
+                                            'completed': ('int', 'int64')})
+        sql = list(sql)
+        self.assertEqual([
+            "ALTER TABLE milestone "
+                "MODIFY completed bigint",
+            ], sql)
+
+    def test_alter_column_types_none(self):
+        connector = MySQLConnector(self.env)
+        sql = connector.alter_column_types('milestone',
+                                           {'due': ('int', 'int')})
+        self.assertEqual([], list(sql))
+
+
+def suite():
+    suite = unittest.TestSuite()
+    suite.addTest(unittest.makeSuite(MySQLTableAlterationSQLTest, 'test'))
+    return suite
+
+
+if __name__ == '__main__':
+    unittest.main(defaultTest='suite')
diff --git a/trac/db/tests/postgres_test.py b/trac/db/tests/postgres_test.py
--- a/trac/db/tests/postgres_test.py
+++ b/trac/db/tests/postgres_test.py
@@ -11,7 +11,6 @@
 class PostgresTableCreationSQLTest(unittest.TestCase):
     def setUp(self):
         self.env = EnvironmentStub()
-        self.db = self.env.get_db_cnx()
     
     def _unroll_generator(self, generator):
         items = []
@@ -82,8 +81,46 @@
         self.assertEqual(index_sql, sql_commands[1])
 
 
+class PostgresTableAlterationSQLTest(unittest.TestCase):
+    def setUp(self):
+        self.env = EnvironmentStub()
+    
+    def test_alter_column_types(self):
+        connector = PostgreSQLConnector(self.env)
+        sql = connector.alter_column_types('milestone',
+                                           {'due': ('int', 'int64'),
+                                            'completed': ('int', 'int64')})
+        sql = list(sql)
+        self.assertEqual([
+            "ALTER TABLE milestone "
+                "ALTER COLUMN completed TYPE bigint, "
+                "ALTER COLUMN due TYPE bigint",
+            ], sql)
+
+    def test_alter_column_types_same(self):
+        connector = PostgreSQLConnector(self.env)
+        sql = connector.alter_column_types('milestone',
+                                           {'due': ('int', 'int'),
+                                            'completed': ('int', 'int64')})
+        sql = list(sql)
+        self.assertEqual([
+            "ALTER TABLE milestone "
+                "ALTER COLUMN completed TYPE bigint",
+            ], sql)
+
+    def test_alter_column_types_none(self):
+        connector = PostgreSQLConnector(self.env)
+        sql = connector.alter_column_types('milestone',
+                                           {'due': ('int', 'int')})
+        self.assertEqual([], list(sql))
+
+
 def suite():
-    return unittest.makeSuite(PostgresTableCreationSQLTest, 'test')
+    suite = unittest.TestSuite()
+    suite.addTest(unittest.makeSuite(PostgresTableCreationSQLTest, 'test'))
+    suite.addTest(unittest.makeSuite(PostgresTableAlterationSQLTest, 'test'))
+    return suite
+
 
 if __name__ == '__main__':
     unittest.main(defaultTest='suite')
diff --git a/trac/db_default.py b/trac/db_default.py
--- a/trac/db_default.py
+++ b/trac/db_default.py
@@ -17,7 +17,7 @@
 from trac.db import Table, Column, Index
 
 # Database version identifier. Used for automatic upgrades.
-db_version = 22
+db_version = 23
 
 def __mkreports(reports):
     """Utility function used to create report data in same syntax as the
@@ -67,7 +67,7 @@
         Column('id'),
         Column('filename'),
         Column('size', type='int'),
-        Column('time', type='int'),
+        Column('time', type='int64'),
         Column('description'),
         Column('author'),
         Column('ipnr')],
@@ -76,7 +76,7 @@
     Table('wiki', key=('name', 'version'))[
         Column('name'),
         Column('version', type='int'),
-        Column('time', type='int'),
+        Column('time', type='int64'),
         Column('author'),
         Column('ipnr'),
         Column('text'),
@@ -87,7 +87,7 @@
     # Version control cache
     Table('revision', key='rev')[
         Column('rev'),
-        Column('time', type='int'),
+        Column('time', type='int64'),
         Column('author'),
         Column('message'),
         Index(['time'])],
@@ -104,8 +104,8 @@
     Table('ticket', key='id')[
         Column('id', auto_increment=True),
         Column('type'),
-        Column('time', type='int'),
-        Column('changetime', type='int'),
+        Column('time', type='int64'),
+        Column('changetime', type='int64'),
         Column('component'),
         Column('severity'),
         Column('priority'),
@@ -123,7 +123,7 @@
         Index(['status'])],    
     Table('ticket_change', key=('ticket', 'time', 'field'))[
         Column('ticket', type='int'),
-        Column('time', type='int'),
+        Column('time', type='int64'),
         Column('author'),
         Column('field'),
         Column('oldvalue'),
@@ -144,12 +144,12 @@
         Column('description')],
     Table('milestone', key='name')[
         Column('name'),
-        Column('due', type='int'),
-        Column('completed', type='int'),
+        Column('due', type='int64'),
+        Column('completed', type='int64'),
         Column('description')],
     Table('version', key='name')[
         Column('name'),
-        Column('time', type='int'),
+        Column('time', type='int64'),
         Column('description')],
 
     # Report system
diff --git a/trac/ticket/model.py b/trac/ticket/model.py
--- a/trac/ticket/model.py
+++ b/trac/ticket/model.py
@@ -26,7 +26,7 @@
 from trac.ticket.api import TicketSystem
 from trac.util import embedded_numbers, partition
 from trac.util.text import empty
-from trac.util.datefmt import utc, utcmax, to_timestamp
+from trac.util.datefmt import from_utimestamp, to_utimestamp, utc, utcmax
 from trac.util.translation import _
 
 __all__ = ['Ticket', 'Type', 'Status', 'Resolution', 'Priority', 'Severity',
@@ -114,7 +114,7 @@
         for i, field in enumerate(std_fields):
             value = row[i]
             if field in self.time_fields:
-                self.values[field] = datetime.fromtimestamp(value or 0, utc)
+                self.values[field] = from_utimestamp(value)
             elif value is None:
                 self.values[field] = empty
             else:
@@ -201,7 +201,7 @@
         values = dict(self.values)
         for field in self.time_fields:
             if field in values:
-                values[field] = to_timestamp(values[field])
+                values[field] = to_utimestamp(values[field])
         
         # Insert ticket record
         std_fields = []
@@ -251,7 +251,7 @@
         cursor = db.cursor()
         if when is None:
             when = datetime.now(utc)
-        when_ts = to_timestamp(when)
+        when_ts = to_utimestamp(when)
 
         if 'component' in self.values:
             # If the component is changed on a 'new' ticket then owner field
@@ -331,7 +331,7 @@
         db = self._get_db(db)
         cursor = db.cursor()
         sid = str(self.id)
-        when_ts = when and to_timestamp(when) or 0
+        when_ts = to_utimestamp(when)
         if when_ts:
             cursor.execute("SELECT time,author,field,oldvalue,newvalue,"
                            "1 AS permanent FROM ticket_change "
@@ -359,8 +359,8 @@
                            (self.id, sid, sid))
         log = []
         for t, author, field, oldvalue, newvalue, permanent in cursor:
-            log.append((datetime.fromtimestamp(int(t), utc), author, field,
-                       oldvalue or '', newvalue or '', permanent))
+            log.append((from_utimestamp(t), author, field,
+                        oldvalue or '', newvalue or '', permanent))
         return log
 
     def delete(self, db=None):
@@ -389,7 +389,7 @@
                            "WHERE ticket=%s AND time=%s",
                            (self.id, ts))
             fields = {}
-            change = {'date': datetime.fromtimestamp(int(ts), utc),
+            change = {'date': from_utimestamp(ts),
                       'author': author, 'fields': fields}
             for field, author, old, new in cursor:
                 fields[field] = {'author': author, 'old': old, 'new': new}
@@ -399,10 +399,10 @@
         """Modify a ticket comment specified by its date, while keeping a
         history of edits.
         """
-        ts = to_timestamp(cdate)
+        ts = to_utimestamp(cdate)
         if when is None:
             when = datetime.now(utc)
-        when_ts = to_timestamp(when)
+        when_ts = to_utimestamp(when)
         
         db, handle_ta = self._get_db_for_write(db)
         cursor = db.cursor()
@@ -444,13 +444,13 @@
                            (self.id, ts0, db.like_escape('_comment') + '%'))
             for field, author, comment, ts in cursor:
                 rev = int(field[8:])
-                history.append((rev, datetime.fromtimestamp(int(ts0), utc),
-                                author0, comment))
+                history.append((rev, from_utimestamp(long(ts0)), author0,
+                                comment))
                 ts0, author0 = ts, author
             history.sort()
             rev = history and (history[-1][0] + 1) or 0
-            history.append((rev, datetime.fromtimestamp(int(ts0), utc),
-                            author0, last_comment))
+            history.append((rev, from_utimestamp(long(ts0)), author0,
+                            last_comment))
         return history
 
     def _find_comment(self, cnum, fields, db):
@@ -784,9 +784,8 @@
     def _from_database(self, row):
         name, due, completed, description = row
         self.name = name
-        self.due = due and datetime.fromtimestamp(int(due), utc) or None
-        self.completed = completed and \
-                         datetime.fromtimestamp(int(completed), utc) or None
+        self.due = due and from_utimestamp(due) or None
+        self.completed = completed and from_utimestamp(completed) or None
         self.description = description or ''
         self._to_old()
 
@@ -838,8 +837,8 @@
         self.env.log.debug("Creating new milestone '%s'" % self.name)
         cursor.execute("INSERT INTO milestone (name,due,completed,description) "
                        "VALUES (%s,%s,%s,%s)",
-                       (self.name, to_timestamp(self.due), to_timestamp(self.completed),
-                        self.description))
+                       (self.name, to_utimestamp(self.due),
+                        to_utimestamp(self.completed), self.description))
         self._to_old()
         TicketSystem(self.env).reset_ticket_fields(db)
 
@@ -863,8 +862,9 @@
         self.env.log.info('Updating milestone "%s"' % self.name)
         cursor.execute("UPDATE milestone SET name=%s,due=%s,"
                        "completed=%s,description=%s WHERE name=%s",
-                       (self.name, to_timestamp(self.due), to_timestamp(self.completed),
-                        self.description, self._old['name']))
+                       (self.name, to_utimestamp(self.due),
+                        to_utimestamp(self.completed), self.description,
+                        self._old['name']))
         self.env.log.info('Updating milestone field of all tickets '
                           'associated with milestone "%s"' % self.name)
         cursor.execute("UPDATE ticket SET milestone=%s WHERE milestone=%s",
@@ -934,7 +934,7 @@
                 raise ResourceNotFound(_('Version %(name)s does not exist.',
                                          name=name))
             self.name = self._old_name = name
-            self.time = row[0] and datetime.fromtimestamp(int(row[0]), utc) or None
+            self.time = row[0] and from_utimestamp(row[0]) or None
             self.description = row[1] or ''
         else:
             self.name = self._old_name = None
@@ -975,7 +975,7 @@
         self.env.log.debug("Creating new version '%s'" % self.name)
         cursor.execute("INSERT INTO version (name,time,description) "
                        "VALUES (%s,%s,%s)",
-                       (self.name, to_timestamp(self.time), self.description))
+                       (self.name, to_utimestamp(self.time), self.description))
         self._old_name = self.name
         TicketSystem(self.env).reset_ticket_fields(db)
 
@@ -997,7 +997,7 @@
         self.env.log.info('Updating version "%s"' % self.name)
         cursor.execute("UPDATE version SET name=%s,time=%s,description=%s "
                        "WHERE name=%s",
-                       (self.name, to_timestamp(self.time), self.description,
+                       (self.name, to_utimestamp(self.time), self.description,
                         self._old_name))
         if self.name != self._old_name:
             # Update tickets
@@ -1019,7 +1019,7 @@
         for name, time, description in cursor:
             version = cls(env)
             version.name = version._old_name = name
-            version.time = time and datetime.fromtimestamp(int(time), utc) or None
+            version.time = time and from_utimestamp(time) or None
             version.description = description or ''
             versions.append(version)
         def version_order(v):
diff --git a/trac/ticket/query.py b/trac/ticket/query.py
--- a/trac/ticket/query.py
+++ b/trac/ticket/query.py
@@ -31,7 +31,8 @@
 from trac.resource import Resource
 from trac.ticket.api import TicketSystem
 from trac.util import Ranges
-from trac.util.datefmt import format_datetime, parse_date, to_timestamp, utc
+from trac.util.datefmt import format_datetime, from_utimestamp, parse_date, \
+                              to_timestamp, to_utimestamp, utc
 from trac.util.presentation import Paginator
 from trac.util.text import empty, shorten_line, unicode_unquote
 from trac.util.translation import _, tag_
@@ -331,7 +332,7 @@
                 elif val is None:
                     val = '--'
                 elif name in self.time_fields:
-                    val = datetime.fromtimestamp(int(val or 0), utc)
+                    val = from_utimestamp(val)
                 elif field and field['type'] == 'checkbox':
                     try:
                         val = bool(int(val))
@@ -466,7 +467,7 @@
         def get_timestamp(date):
             if date:
                 try:
-                    return to_timestamp(parse_date(date, req.tz))
+                    return to_utimestamp(parse_date(date, req.tz))
                 except TracError, e:
                     errors.append(unicode(e))
             return None
@@ -484,7 +485,7 @@
                                     value.split(';', 1)]
                 else:
                     (start, end) = (value.strip(), '')
-                col_cast = db.cast(col, 'int')
+                col_cast = db.cast(col, 'int64')
                 start = get_timestamp(start)
                 end = get_timestamp(end)
                 if start is not None and end is not None:
diff --git a/trac/ticket/roadmap.py b/trac/ticket/roadmap.py
--- a/trac/ticket/roadmap.py
+++ b/trac/ticket/roadmap.py
@@ -18,7 +18,6 @@
 from StringIO import StringIO
 from datetime import datetime
 import re
-from time import time
 
 from genshi.builder import tag
 
@@ -30,9 +29,9 @@
 from trac.perm import IPermissionRequestor
 from trac.resource import *
 from trac.search import ISearchSource, search_to_sql, shorten_result
-from trac.util.datefmt import parse_date, utc, to_timestamp, to_datetime, \
+from trac.util.datefmt import parse_date, utc, to_utimestamp, \
                               get_date_format_hint, get_datetime_format_hint, \
-                              format_date, format_datetime
+                              format_date, format_datetime, from_utimestamp
 from trac.util.text import CRLF
 from trac.util.translation import _
 from trac.ticket import Milestone, Ticket, TicketSystem, group_milestones
@@ -475,7 +474,7 @@
                                    (ticket.id,))
                     row = cursor.fetchone()
                     if row:
-                        write_utctime('COMPLETED', to_datetime(row[0], utc))
+                        write_utctime('COMPLETED', from_utimestamp(row[0]))
                 write_prop('END', 'VTODO')
         write_prop('END', 'VCALENDAR')
 
@@ -530,11 +529,11 @@
             # TODO: creation and (later) modifications should also be reported
             cursor.execute("SELECT completed,name,description FROM milestone "
                            "WHERE completed>=%s AND completed<=%s",
-                           (to_timestamp(start), to_timestamp(stop)))
+                           (to_utimestamp(start), to_utimestamp(stop)))
             for completed, name, description in cursor:
                 milestone = milestone_realm(id=name)
                 if 'MILESTONE_VIEW' in req.perm(milestone):
-                    yield('milestone', datetime.fromtimestamp(completed, utc),
+                    yield('milestone', from_utimestamp(completed),
                           '', (milestone, description)) # FIXME: author?
 
             # Attachments
@@ -866,10 +865,10 @@
         for name, due, completed, description in cursor:
             milestone = milestone_realm(id=name)
             if 'MILESTONE_VIEW' in req.perm(milestone):
+                dt = (completed and from_utimestamp(completed) or
+                      due and from_utimestamp(due) or datetime.now(utc))
                 yield (get_resource_url(self.env, milestone, req.href),
-                       get_resource_name(self.env, milestone),
-                       datetime.fromtimestamp(
-                           completed or due or time(), utc),
+                       get_resource_name(self.env, milestone), dt,
                        '', shorten_result(description, terms))
         
         # Attachments
diff --git a/trac/ticket/templates/report.rss b/trac/ticket/templates/report.rss
--- a/trac/ticket/templates/report.rss
+++ b/trac/ticket/templates/report.rss
@@ -26,7 +26,7 @@
                 </py:when>
                 <py:when test="col in ('time', 'changetime', 'created', 'modified')">
                   <!-- FIXME: we end up with multiple pubDate -->
-                  <pubDate py:if="cell.value != 'None'">${http_date(fromtimestamp(int(cell.value)))}</pubDate>
+                  <pubDate py:if="cell.value != 'None'">${http_date(from_utimestamp(long(cell.value)))}</pubDate>
                 </py:when>
                 <py:when test="col == 'summary'">
                   <title>#$row.id: $cell.value</title>
diff --git a/trac/ticket/templates/report_view.html b/trac/ticket/templates/report_view.html
--- a/trac/ticket/templates/report_view.html
+++ b/trac/ticket/templates/report_view.html
@@ -147,19 +147,19 @@
 
                         <!--! generic fields -->
                         <py:when test="col == 'time'">
-                          <td class="date" py:attrs="td_attrs">${cell.value != '' and format_time(int(cell.value)) or '--'}
+                          <td class="date" py:attrs="td_attrs">${cell.value != '' and format_time(from_utimestamp(long(cell.value))) or '--'}
                             <hr py:if="fullrow"/>
                           </td>
                         </py:when>
 
                         <py:when test="col in ('date', 'created', 'modified')">
-                          <td class="date" py:attrs="td_attrs">${cell.value != '' and format_date(int(cell.value)) or '--'}
+                          <td class="date" py:attrs="td_attrs">${cell.value != '' and format_date(from_utimestamp(long(cell.value))) or '--'}
                             <hr py:if="fullrow"/>
                           </td>
                         </py:when>
 
                         <py:when test="col == 'datetime'">
-                          <td class="date" py:attrs="td_attrs">${cell.value != '' and format_datetime(int(cell.value)) or '--'}
+                          <td class="date" py:attrs="td_attrs">${cell.value != '' and format_datetime(from_utimestamp(long(cell.value))) or '--'}
                             <hr py:if="fullrow"/>
                           </td>
                         </py:when>
diff --git a/trac/ticket/tests/model.py b/trac/ticket/tests/model.py
--- a/trac/ticket/tests/model.py
+++ b/trac/ticket/tests/model.py
@@ -4,7 +4,7 @@
 from trac.ticket.model import Ticket, Component, Milestone, Priority, Type, Version
 from trac.ticket.api import IMilestoneChangeListener, ITicketChangeListener
 from trac.test import EnvironmentStub
-from trac.util.datefmt import utc, to_timestamp
+from trac.util.datefmt import utc, to_utimestamp
 
 from datetime import datetime
 import unittest
@@ -300,7 +300,7 @@
                        "                        description,author,ipnr) "
                        "VALUES ('ticket',%s,'file.txt',1234,%s,"
                        "        'My file','mark','')",
-                       (str(tkt_id), to_timestamp(t2)))
+                       (str(tkt_id), to_utimestamp(t2)))
         db.commit()
         t3 = datetime(2001, 1, 1, 1, 1, 3, 0, utc)
         ticket.save_changes('jim', 'Other', t3)
@@ -312,6 +312,19 @@
                           sorted(log[1:3]))
         self.assertEqual((t3, 'jim', 'comment', '', 'Other', True), log[3])
 
+    def test_subsecond_change(self):
+        """Perform two ticket changes within a second."""
+        tkt_id = self._insert_ticket('Test', reporter='joe', component='foo')
+        ticket = Ticket(self.env, tkt_id)
+        t1 = datetime(2001, 1, 1, 1, 1, 1, 123456, utc)
+        ticket.save_changes('jane', 'Testing', t1)
+        t2 = datetime(2001, 1, 1, 1, 1, 1, 789012, utc)
+        ticket.save_changes('jim', 'Other', t2)
+        log = ticket.get_changelog()
+        self.assertEqual(2, len(log))
+        self.assertEqual((t1, 'jane', 'comment', '', 'Testing', True), log[0])
+        self.assertEqual((t2, 'jim', 'comment', '', 'Other', True), log[1])
+
     def test_changelog_with_reverted_change(self):
         tkt_id = self._insert_ticket('Test', reporter='joe', component='foo')
         ticket = Ticket(self.env, tkt_id)
@@ -545,7 +558,8 @@
 
         cursor = self.db.cursor()
         cursor.execute("SELECT * FROM milestone WHERE name='Test'")
-        self.assertEqual(('Test', to_timestamp(t1), to_timestamp(t2), 'Foo bar'),
+        self.assertEqual(('Test', to_utimestamp(t1), to_utimestamp(t2),
+                          'Foo bar'),
                          cursor.fetchone())
 
     def test_update_milestone_without_name(self):
diff --git a/trac/ticket/tests/query.py b/trac/ticket/tests/query.py
--- a/trac/ticket/tests/query.py
+++ b/trac/ticket/tests/query.py
@@ -358,8 +358,8 @@
   LEFT OUTER JOIN enum AS priority ON (priority.type='priority' AND priority.name=priority)
 WHERE (((%(cast_time)s>=%%s AND %(cast_time)s<%%s)))
 ORDER BY COALESCE(t.id,0)=0,t.id""" % {
-          'cast_time': self.env.get_db_cnx().cast('t.time', 'int')})
-        self.assertEqual([1217548800, 1220227200], args)
+          'cast_time': self.env.get_db_cnx().cast('t.time', 'int64')})
+        self.assertEqual([1217548800000000L, 1220227200000000L], args)
         tickets = query.execute(self.req)
 
     def test_constrained_by_time_range_exclusion(self):
@@ -371,8 +371,8 @@
   LEFT OUTER JOIN enum AS priority ON (priority.type='priority' AND priority.name=priority)
 WHERE ((NOT (%(cast_time)s>=%%s AND %(cast_time)s<%%s)))
 ORDER BY COALESCE(t.id,0)=0,t.id""" % {
-          'cast_time': self.env.get_db_cnx().cast('t.time', 'int')})
-        self.assertEqual([1217548800, 1220227200], args)
+          'cast_time': self.env.get_db_cnx().cast('t.time', 'int64')})
+        self.assertEqual([1217548800000000L, 1220227200000000L], args)
         tickets = query.execute(self.req)
 
     def test_constrained_by_time_range_open_right(self):
@@ -384,8 +384,8 @@
   LEFT OUTER JOIN enum AS priority ON (priority.type='priority' AND priority.name=priority)
 WHERE ((%(cast_time)s>=%%s))
 ORDER BY COALESCE(t.id,0)=0,t.id""" % {
-          'cast_time': self.env.get_db_cnx().cast('t.time', 'int')})
-        self.assertEqual([1217548800], args)
+          'cast_time': self.env.get_db_cnx().cast('t.time', 'int64')})
+        self.assertEqual([1217548800000000L], args)
         tickets = query.execute(self.req)
 
     def test_constrained_by_time_range_open_left(self):
@@ -397,8 +397,8 @@
   LEFT OUTER JOIN enum AS priority ON (priority.type='priority' AND priority.name=priority)
 WHERE ((%(cast_time)s<%%s))
 ORDER BY COALESCE(t.id,0)=0,t.id""" % {
-          'cast_time': self.env.get_db_cnx().cast('t.time', 'int')})
-        self.assertEqual([1220227200], args)
+          'cast_time': self.env.get_db_cnx().cast('t.time', 'int64')})
+        self.assertEqual([1220227200000000L], args)
         tickets = query.execute(self.req)
 
     def test_constrained_by_time_range_modified(self):
@@ -410,8 +410,8 @@
   LEFT OUTER JOIN enum AS priority ON (priority.type='priority' AND priority.name=priority)
 WHERE (((%(cast_changetime)s>=%%s AND %(cast_changetime)s<%%s)))
 ORDER BY COALESCE(t.id,0)=0,t.id""" % {
-          'cast_changetime': self.env.get_db_cnx().cast('t.changetime', 'int')})
-        self.assertEqual([1217548800, 1220227200], args)
+          'cast_changetime': self.env.get_db_cnx().cast('t.changetime', 'int64')})
+        self.assertEqual([1217548800000000L, 1220227200000000L], args)
         tickets = query.execute(self.req)
 
     def test_constrained_by_keywords(self):
diff --git a/trac/ticket/web_ui.py b/trac/ticket/web_ui.py
--- a/trac/ticket/web_ui.py
+++ b/trac/ticket/web_ui.py
@@ -36,7 +36,8 @@
 from trac.timeline.api import ITimelineEventProvider
 from trac.util import get_reporter_id
 from trac.util.compat import any
-from trac.util.datefmt import format_datetime, to_timestamp, utc
+from trac.util.datefmt import format_datetime, from_utimestamp, \
+                              to_utimestamp, utc
 from trac.util.text import exception_to_unicode, obfuscate_email_address,  \
                            shorten_line, to_unicode
 from trac.util.presentation import separated
@@ -214,7 +215,7 @@
                            ': ',
                            ticketsystem.format_summary(summary, status,
                                                        resolution, type)),
-                       datetime.fromtimestamp(ts, utc), author,
+                       from_utimestamp(ts), author,
                        shorten_result(desc, terms))
         
         # Attachments
@@ -231,8 +232,8 @@
                 yield ('ticket_details', _('Ticket updates'), False)
 
     def get_timeline_events(self, req, start, stop, filters):
-        ts_start = to_timestamp(start)
-        ts_stop = to_timestamp(stop)
+        ts_start = to_utimestamp(start)
+        ts_stop = to_utimestamp(stop)
 
         status_map = {'new': ('newticket', N_('created')),
                       'reopened': ('reopenedticket', N_('reopened')),
@@ -268,7 +269,7 @@
             else:
                 return None
             kind, verb = status_map[status]
-            return (kind, datetime.fromtimestamp(ts, utc), author,
+            return (kind, from_utimestamp(ts), author,
                     (ticket, verb, info, summary, status, resolution, type,
                      description, comment, cid))
 
@@ -1643,8 +1644,7 @@
                 rev = int(field[8:])
                 comment_history.setdefault(rev, {}).update({'comment': old})
                 comment_history.setdefault(rev + 1, {}).update(
-                        {'author': author,
-                         'date': datetime.fromtimestamp(int(new), utc)})
+                        {'author': author, 'date': from_utimestamp(long(new))})
             elif old or new:
                 current['fields'][field] = {'old': old, 'new': new}
         if current:
diff --git a/trac/timeline/web_ui.py b/trac/timeline/web_ui.py
--- a/trac/timeline/web_ui.py
+++ b/trac/timeline/web_ui.py
@@ -29,7 +29,7 @@
 from trac.perm import IPermissionRequestor
 from trac.timeline.api import ITimelineEventProvider
 from trac.util.datefmt import format_date, format_datetime, parse_date, \
-                              to_timestamp, utc, pretty_timedelta
+                              to_utimestamp, utc, pretty_timedelta
 from trac.util.text import exception_to_unicode, to_unicode
 from trac.util.translation import _, tag_
 from trac.web import IRequestHandler, IRequestFilter
@@ -106,7 +106,8 @@
                 precision = timedelta(hours=1)
             else:
                 precision = None
-        fromdate = fromdate.replace(hour=23, minute=59, second=59)
+        fromdate = fromdate.replace(hour=23, minute=59, second=59,
+                                    microsecond=999999)
         try:
             daysback = int(req.args.get('daysback', ''))
         except ValueError:
@@ -312,11 +313,9 @@
                 kind, date, author, data = event
             render = lambda field, context: \
                     provider.render_timeline_event(context, field, event)
-        if isinstance(date, datetime):
-            dateuid = to_timestamp(date)
-        else:
-            dateuid = date
+        if not isinstance(date, datetime):
             date = datetime.fromtimestamp(date, utc)
+        dateuid = to_utimestamp(date)
         return {'kind': kind, 'author': author, 'date': date,
                 'dateuid': dateuid, 'render': render, 'event': event,
                 'data': data, 'provider': provider}
diff --git a/trac/upgrades/db15.py b/trac/upgrades/db15.py
--- a/trac/upgrades/db15.py
+++ b/trac/upgrades/db15.py
@@ -10,7 +10,7 @@
         Column('authenticated', type='int'),
         Column('var_name'),
         Column('var_value')]
-    db_backend, _ = DatabaseManager(env)._get_connector()
+    db_backend, _ = DatabaseManager(env).get_connector()
     for stmt in db_backend.to_sql(session_table):
         cursor.execute(stmt)
 
diff --git a/trac/upgrades/db17.py b/trac/upgrades/db17.py
--- a/trac/upgrades/db17.py
+++ b/trac/upgrades/db17.py
@@ -16,7 +16,7 @@
         Column('base_rev'),
         Index(['rev'])
     ]
-    db_connector, _ = DatabaseManager(env)._get_connector()
+    db_connector, _ = DatabaseManager(env).get_connector()
     for stmt in db_connector.to_sql(table):
         cursor.execute(stmt)
 
diff --git a/trac/upgrades/db18.py b/trac/upgrades/db18.py
--- a/trac/upgrades/db18.py
+++ b/trac/upgrades/db18.py
@@ -29,7 +29,7 @@
                 Index(['ticket']),
                 Index(['time'])]]
     
-    db_connector, _ = DatabaseManager(env)._get_connector()
+    db_connector, _ = DatabaseManager(env).get_connector()
     for table in tables:
         for stmt in db_connector.to_sql(table):
             cursor.execute(stmt)
diff --git a/trac/upgrades/db19.py b/trac/upgrades/db19.py
--- a/trac/upgrades/db19.py
+++ b/trac/upgrades/db19.py
@@ -13,7 +13,7 @@
         Column('query'),
         Column('description')
     ]
-    db_connector, _ = DatabaseManager(env)._get_connector()
+    db_connector, _ = DatabaseManager(env).get_connector()
     for stmt in db_connector.to_sql(table):
         cursor.execute(stmt)
 
diff --git a/trac/upgrades/db22.py b/trac/upgrades/db22.py
--- a/trac/upgrades/db22.py
+++ b/trac/upgrades/db22.py
@@ -6,6 +6,6 @@
         Column('id'),
         Column('generation', type='int')
     ]
-    db_connector, _ = DatabaseManager(env)._get_connector()
+    db_connector, _ = DatabaseManager(env).get_connector()
     for stmt in db_connector.to_sql(table):
         cursor.execute(stmt)
diff --git a/trac/upgrades/db23.py b/trac/upgrades/db23.py
new file mode 100644
--- /dev/null
+++ b/trac/upgrades/db23.py
@@ -0,0 +1,34 @@
+from trac.db import DatabaseManager
+
+
+def do_upgrade(env, ver, cursor):
+    """Convert time values from integer seconds to integer microseconds."""
+    tables = [
+        ('attachment', {'time': ('int', 'int64')}),
+        ('wiki', {'time': ('int', 'int64')}),
+        ('revision', {'time': ('int', 'int64')}),
+        ('ticket', {'time': ('int', 'int64'),
+                    'changetime': ('int', 'int64')}),
+        ('ticket_change', {'time': ('int', 'int64')}),
+        ('milestone', {'due': ('int', 'int64'),
+                       'completed': ('int', 'int64')}),
+        ('version', {'time': ('int', 'int64')}),
+    ]
+    
+    db_connector, _ = DatabaseManager(env).get_connector()
+    db = env.get_db_cnx()
+    for table, columns in tables:
+        # Alter column types
+        for sql in db_connector.alter_column_types(table, columns):
+            cursor.execute(sql)
+        
+        # Convert timestamps to microseconds
+        cursor.execute("UPDATE %s SET %s" % (table,
+                        ', '.join("%s=%s*1000000" % (column, column)
+                                  for column in columns)))
+    
+    # Convert comment edit timestamps to microseconds
+    cursor.execute("UPDATE ticket_change SET newvalue=%s*1000000 "
+                   "WHERE field %s" % (db.cast('newvalue', 'int64'),
+                                       db.like()),
+                   ('_comment%',))
diff --git a/trac/util/datefmt.py b/trac/util/datefmt.py
--- a/trac/util/datefmt.py
+++ b/trac/util/datefmt.py
@@ -61,6 +61,17 @@
     else:
         return 0
 
+def to_utimestamp(dt):
+    """Return a microsecond POSIX timestamp for the given `datetime`."""
+    if not dt:
+        return 0
+    diff = dt - _epoc
+    return (diff.days * 86400000000L + diff.seconds * 1000000
+            + diff.microseconds)
+
+def from_utimestamp(ts):
+    """Return the `datetime` for the given microsecond POSIX timestamp."""
+    return _epoc + timedelta(microseconds=ts or 0)
 
 # -- formatting
 
diff --git a/trac/util/tests/datefmt.py b/trac/util/tests/datefmt.py
--- a/trac/util/tests/datefmt.py
+++ b/trac/util/tests/datefmt.py
@@ -113,6 +113,14 @@
                          datefmt.format_date(a_date, format='%Y-%m-%d'))
 
 
+class UTimestampTestCase(unittest.TestCase):
+    
+    def test_sub_second(self):
+        t = datetime.datetime(2001, 2, 3, 4, 5, 6, 123456, datefmt.utc)
+        ts = datefmt.to_utimestamp(t)
+        self.assertEqual(t, datefmt.from_utimestamp(ts))
+
+
 def suite():
     suite = unittest.TestSuite()
     if PytzTestCase:
@@ -120,6 +128,7 @@
     else:
         print "SKIP: utils/tests/datefmt.py (no pytz installed)"
     suite.addTest(unittest.makeSuite(DateFormatTestCase))
+    suite.addTest(unittest.makeSuite(UTimestampTestCase))
     return suite
 
 if __name__ == '__main__':
diff --git a/trac/versioncontrol/cache.py b/trac/versioncontrol/cache.py
--- a/trac/versioncontrol/cache.py
+++ b/trac/versioncontrol/cache.py
@@ -14,12 +14,11 @@
 #
 # Author: Christopher Lenz <cmlenz@gmx.de>
 
-from datetime import datetime
 import os
 import posixpath
 
 from trac.core import TracError
-from trac.util.datefmt import utc, to_timestamp
+from trac.util.datefmt import from_utimestamp, to_utimestamp
 from trac.util.translation import _
 from trac.versioncontrol import Changeset, Node, Repository, Authorizer, \
                                 NoSuchChangeset
@@ -67,7 +66,7 @@
         cursor.execute("SELECT rev FROM revision "
                        "WHERE time >= %s AND time < %s "
                        "ORDER BY time DESC, rev DESC",
-                       (to_timestamp(start), to_timestamp(stop)))
+                       (to_utimestamp(start), to_utimestamp(stop)))
         for rev, in cursor:
             try:
                 if self.authz.has_permission_for_changeset(rev):
@@ -80,7 +79,7 @@
         db = self.getdb()
         cursor = db.cursor()
         cursor.execute("UPDATE revision SET time=%s, author=%s, message=%s "
-                       "WHERE rev=%s", (to_timestamp(cset.date),
+                       "WHERE rev=%s", (to_utimestamp(cset.date),
                                         cset.author, cset.message,
                                         (str(cset.rev))))
         db.commit()
@@ -187,7 +186,7 @@
                                        " (rev,time,author,message) "
                                        "VALUES (%s,%s,%s,%s)",
                                        (str(next_youngest),
-                                        to_timestamp(cset.date),
+                                        to_utimestamp(cset.date),
                                         cset.author, cset.message))
                     except Exception, e: # *another* 1.1. resync attempt won 
                         self.log.warning('Revision %s already cached: %s' %
@@ -339,11 +338,10 @@
         cursor = db.cursor()
         cursor.execute("SELECT time,author,message FROM revision "
                        "WHERE rev=%s", (str(rev),))
-        row = cursor.fetchone()
-        if row:
-            _date, author, message = row
-            date = datetime.fromtimestamp(_date, utc)
+        for _date, author, message in cursor:
+            date = from_utimestamp(_date)
             Changeset.__init__(self, rev, message, author, date)
+            break
         else:
             raise NoSuchChangeset(rev)
         self.scope = getattr(repos, 'scope', '')
diff --git a/trac/versioncontrol/svn_fs.py b/trac/versioncontrol/svn_fs.py
--- a/trac/versioncontrol/svn_fs.py
+++ b/trac/versioncontrol/svn_fs.py
@@ -46,7 +46,6 @@
 import os.path
 import weakref
 import posixpath
-from datetime import datetime
 
 from trac.config import ListOption
 from trac.core import *
@@ -58,7 +57,7 @@
 from trac.util import embedded_numbers
 from trac.util.text import exception_to_unicode, to_unicode
 from trac.util.translation import _
-from trac.util.datefmt import utc
+from trac.util.datefmt import from_utimestamp
 
 
 application_pool = None
@@ -783,8 +782,7 @@
                                  core.SVN_PROP_REVISION_DATE, self.pool())
         if not _date:
             return None
-        ts = core.svn_time_from_cstring(_date, self.pool()) / 1000000
-        return datetime.fromtimestamp(ts, utc)
+        return from_utimestamp(core.svn_time_from_cstring(_date, self.pool()))
 
     def _get_prop(self, name):
         return fs.node_prop(self.root, self._scoped_path_utf8, name,
@@ -849,8 +847,8 @@
         author = author and to_unicode(author, 'utf-8')
         _date = self._get_prop(core.SVN_PROP_REVISION_DATE)
         if _date:
-            ts = core.svn_time_from_cstring(_date, self.pool()) / 1000000
-            date = datetime.fromtimestamp(ts, utc)
+            ts = core.svn_time_from_cstring(_date, self.pool())
+            date = from_utimestamp(ts)
         else:
             date = None
         Changeset.__init__(self, rev, message, author, date)
diff --git a/trac/versioncontrol/tests/cache.py b/trac/versioncontrol/tests/cache.py
--- a/trac/versioncontrol/tests/cache.py
+++ b/trac/versioncontrol/tests/cache.py
@@ -18,7 +18,7 @@
 
 from trac.log import logger_factory
 from trac.test import Mock, InMemoryDatabase
-from trac.util.datefmt import to_timestamp, utc
+from trac.util.datefmt import to_utimestamp, utc
 from trac.versioncontrol import Repository, Changeset, Node, NoSuchChangeset
 from trac.versioncontrol.cache import CachedRepository
 
@@ -73,8 +73,8 @@
 
         cursor = self.db.cursor()
         cursor.execute("SELECT rev,time,author,message FROM revision")
-        self.assertEquals(('0', to_timestamp(t1), '', ''), cursor.fetchone())
-        self.assertEquals(('1', to_timestamp(t2), 'joe', 'Import'), cursor.fetchone())
+        self.assertEquals(('0', to_utimestamp(t1), '', ''), cursor.fetchone())
+        self.assertEquals(('1', to_utimestamp(t2), 'joe', 'Import'), cursor.fetchone())
         self.assertEquals(None, cursor.fetchone())
         cursor.execute("SELECT rev,path,node_type,change_type,base_path,"
                        "base_rev FROM node_change")
@@ -90,9 +90,9 @@
         t3 = datetime(2003, 1, 1, 1, 1, 1, 0, utc)
         cursor = self.db.cursor()
         cursor.execute("INSERT INTO revision (rev,time,author,message) "
-                       "VALUES (0,%s,'','')", (to_timestamp(t1),))
+                       "VALUES (0,%s,'','')", (to_utimestamp(t1),))
         cursor.execute("INSERT INTO revision (rev,time,author,message) "
-                       "VALUES (1,%s,'joe','Import')", (to_timestamp(t2),))
+                       "VALUES (1,%s,'joe','Import')", (to_utimestamp(t2),))
         cursor.executemany("INSERT INTO node_change (rev,path,node_type,"
                            "change_type,base_path,base_rev) "
                            "VALUES ('1',%s,%s,%s,%s,%s)",
@@ -114,7 +114,7 @@
 
         cursor = self.db.cursor()
         cursor.execute("SELECT time,author,message FROM revision WHERE rev='2'")
-        self.assertEquals((to_timestamp(t3), 'joe', 'Update'), cursor.fetchone())
+        self.assertEquals((to_utimestamp(t3), 'joe', 'Update'), cursor.fetchone())
         self.assertEquals(None, cursor.fetchone())
         cursor.execute("SELECT path,node_type,change_type,base_path,base_rev "
                        "FROM node_change WHERE rev='2'")
@@ -127,9 +127,9 @@
         t2 = datetime(2002, 1, 1, 1, 1, 1, 0, utc)
         cursor = self.db.cursor()
         cursor.execute("INSERT INTO revision (rev,time,author,message) "
-                       "VALUES (0,%s,'','')", (to_timestamp(t1),))
+                       "VALUES (0,%s,'','')", (to_utimestamp(t1),))
         cursor.execute("INSERT INTO revision (rev,time,author,message) "
-                       "VALUES (1,%s,'joe','Import')", (to_timestamp(t2),))
+                       "VALUES (1,%s,'joe','Import')", (to_utimestamp(t2),))
         cursor.executemany("INSERT INTO node_change (rev,path,node_type,"
                            "change_type,base_path,base_rev) "
                            "VALUES ('1',%s,%s,%s,%s,%s)",
diff --git a/trac/versioncontrol/tests/svn_fs.py b/trac/versioncontrol/tests/svn_fs.py
--- a/trac/versioncontrol/tests/svn_fs.py
+++ b/trac/versioncontrol/tests/svn_fs.py
@@ -145,14 +145,14 @@
         self.assertEqual(u'/tête', node.path)
         self.assertEqual(Node.DIRECTORY, node.kind)
         self.assertEqual(HEAD, node.rev)
-        self.assertEqual(datetime(2007, 4, 30, 17, 45, 26, 0, utc),
+        self.assertEqual(datetime(2007, 4, 30, 17, 45, 26, 234375, utc),
                          node.last_modified)
         node = self.repos.get_node(u'/tête/README.txt')
         self.assertEqual('README.txt', node.name)
         self.assertEqual(u'/tête/README.txt', node.path)
         self.assertEqual(Node.FILE, node.kind)
         self.assertEqual(3, node.rev)
-        self.assertEqual(datetime(2005, 4, 1, 13, 24, 58, 0, utc), node.last_modified)
+        self.assertEqual(datetime(2005, 4, 1, 13, 24, 58, 234643, utc), node.last_modified)
 
     def test_get_node_specific_rev(self):
         node = self.repos.get_node(u'/tête', 1)
@@ -160,13 +160,13 @@
         self.assertEqual(u'/tête', node.path)
         self.assertEqual(Node.DIRECTORY, node.kind)
         self.assertEqual(1, node.rev)
-        self.assertEqual(datetime(2005, 4, 1, 10, 0, 52, 0, utc), node.last_modified)
+        self.assertEqual(datetime(2005, 4, 1, 10, 0, 52, 353248, utc), node.last_modified)
         node = self.repos.get_node(u'/tête/README.txt', 2)
         self.assertEqual('README.txt', node.name)
         self.assertEqual(u'/tête/README.txt', node.path)
         self.assertEqual(Node.FILE, node.kind)
         self.assertEqual(2, node.rev)
-        self.assertEqual(datetime(2005, 4, 1, 13, 12, 18, 0, utc), node.last_modified)
+        self.assertEqual(datetime(2005, 4, 1, 13, 12, 18, 216267, utc), node.last_modified)
 
     def test_get_dir_entries(self):
         node = self.repos.get_node(u'/tête')
@@ -383,7 +383,7 @@
         self.assertEqual(0, chgset.rev)
         self.assertEqual('', chgset.message)
         self.assertEqual('', chgset.author)
-        self.assertEqual(datetime(2005, 4, 1, 9, 57, 41, 0, utc), chgset.date)
+        self.assertEqual(datetime(2005, 4, 1, 9, 57, 41, 312767, utc), chgset.date)
         self.assertRaises(StopIteration, chgset.get_changes().next)
 
     def test_changeset_added_dirs(self):
@@ -391,7 +391,7 @@
         self.assertEqual(1, chgset.rev)
         self.assertEqual('Initial directory layout.', chgset.message)
         self.assertEqual('john', chgset.author)
-        self.assertEqual(datetime(2005, 4, 1, 10, 0, 52, 0, utc), chgset.date)
+        self.assertEqual(datetime(2005, 4, 1, 10, 0, 52, 353248, utc), chgset.date)
 
         changes = chgset.get_changes()
         self.assertEqual(('branches', Node.DIRECTORY, Changeset.ADD, None, -1),
@@ -407,7 +407,7 @@
         self.assertEqual(3, chgset.rev)
         self.assertEqual('Fixed README.\n', chgset.message)
         self.assertEqual('kate', chgset.author)
-        self.assertEqual(datetime(2005, 4, 1, 13, 24, 58, 0, utc), chgset.date)
+        self.assertEqual(datetime(2005, 4, 1, 13, 24, 58, 234643, utc), chgset.date)
 
         changes = chgset.get_changes()
         self.assertEqual((u'tête/README.txt', Node.FILE, Changeset.EDIT,
@@ -419,7 +419,7 @@
         self.assertEqual(5, chgset.rev)
         self.assertEqual('Moved directories.', chgset.message)
         self.assertEqual('kate', chgset.author)
-        self.assertEqual(datetime(2005, 4, 1, 16, 25, 39, 0, utc), chgset.date)
+        self.assertEqual(datetime(2005, 4, 1, 16, 25, 39, 658099, utc), chgset.date)
 
         changes = chgset.get_changes()
         self.assertEqual((u'tête/dir1/dir2', Node.DIRECTORY, Changeset.MOVE,
@@ -433,7 +433,7 @@
         self.assertEqual(6, chgset.rev)
         self.assertEqual('More things to read', chgset.message)
         self.assertEqual('john', chgset.author)
-        self.assertEqual(datetime(2005, 4, 1, 18, 56, 46, 0, utc), chgset.date)
+        self.assertEqual(datetime(2005, 4, 1, 18, 56, 46, 985846, utc), chgset.date)
 
         changes = chgset.get_changes()
         self.assertEqual((u'tête/README2.txt', Node.FILE, Changeset.COPY,
@@ -550,13 +550,13 @@
         self.assertEqual('/dir1', node.path)
         self.assertEqual(Node.DIRECTORY, node.kind)
         self.assertEqual(5, node.rev)
-        self.assertEqual(datetime(2005, 4, 1, 16, 25, 39, 0, utc), node.last_modified)
+        self.assertEqual(datetime(2005, 4, 1, 16, 25, 39, 658099, utc), node.last_modified)
         node = self.repos.get_node('/README.txt')
         self.assertEqual('README.txt', node.name)
         self.assertEqual('/README.txt', node.path)
         self.assertEqual(Node.FILE, node.kind)
         self.assertEqual(3, node.rev)
-        self.assertEqual(datetime(2005, 4, 1, 13, 24, 58, 0, utc), node.last_modified)
+        self.assertEqual(datetime(2005, 4, 1, 13, 24, 58, 234643, utc), node.last_modified)
 
     def test_get_node_specific_rev(self):
         node = self.repos.get_node('/dir1', 4)
@@ -564,13 +564,13 @@
         self.assertEqual('/dir1', node.path)
         self.assertEqual(Node.DIRECTORY, node.kind)
         self.assertEqual(4, node.rev)
-        self.assertEqual(datetime(2005, 4, 1, 15, 42, 35, 0, utc), node.last_modified)
+        self.assertEqual(datetime(2005, 4, 1, 15, 42, 35, 450595, utc), node.last_modified)
         node = self.repos.get_node('/README.txt', 2)
         self.assertEqual('README.txt', node.name)
         self.assertEqual('/README.txt', node.path)
         self.assertEqual(Node.FILE, node.kind)
         self.assertEqual(2, node.rev)
-        self.assertEqual(datetime(2005, 4, 1, 13, 12, 18, 0, utc), node.last_modified)
+        self.assertEqual(datetime(2005, 4, 1, 13, 12, 18, 216267, utc), node.last_modified)
 
     def test_get_dir_entries(self):
         node = self.repos.get_node('/')
@@ -675,7 +675,7 @@
         self.assertEqual(0, chgset.rev)
         self.assertEqual('', chgset.message)
         self.assertEqual('', chgset.author)
-        self.assertEqual(datetime(2005, 4, 1, 9, 57, 41, 0, utc), chgset.date)
+        self.assertEqual(datetime(2005, 4, 1, 9, 57, 41, 312767, utc), chgset.date)
         self.assertRaises(StopIteration, chgset.get_changes().next)
 
     def test_changeset_added_dirs(self):
@@ -683,7 +683,7 @@
         self.assertEqual(4, chgset.rev)
         self.assertEqual('More directories.', chgset.message)
         self.assertEqual('john', chgset.author)
-        self.assertEqual(datetime(2005, 4, 1, 15, 42, 35, 0, utc), chgset.date)
+        self.assertEqual(datetime(2005, 4, 1, 15, 42, 35, 450595, utc), chgset.date)
 
         changes = chgset.get_changes()
         self.assertEqual(('dir1', Node.DIRECTORY, 'add', None, -1),
@@ -699,7 +699,7 @@
         self.assertEqual(3, chgset.rev)
         self.assertEqual('Fixed README.\n', chgset.message)
         self.assertEqual('kate', chgset.author)
-        self.assertEqual(datetime(2005, 4, 1, 13, 24, 58, 0, utc), chgset.date)
+        self.assertEqual(datetime(2005, 4, 1, 13, 24, 58, 234643, utc), chgset.date)
 
         changes = chgset.get_changes()
         self.assertEqual(('README.txt', Node.FILE, Changeset.EDIT,
@@ -711,7 +711,7 @@
         self.assertEqual(5, chgset.rev)
         self.assertEqual('Moved directories.', chgset.message)
         self.assertEqual('kate', chgset.author)
-        self.assertEqual(datetime(2005, 4, 1, 16, 25, 39, 0, utc), chgset.date)
+        self.assertEqual(datetime(2005, 4, 1, 16, 25, 39, 658099, utc), chgset.date)
 
         changes = chgset.get_changes()
         self.assertEqual(('dir1/dir2', Node.DIRECTORY, Changeset.MOVE,
@@ -725,7 +725,7 @@
         self.assertEqual(6, chgset.rev)
         self.assertEqual('More things to read', chgset.message)
         self.assertEqual('john', chgset.author)
-        self.assertEqual(datetime(2005, 4, 1, 18, 56, 46, 0, utc), chgset.date)
+        self.assertEqual(datetime(2005, 4, 1, 18, 56, 46, 985846, utc), chgset.date)
 
         changes = chgset.get_changes()
         self.assertEqual(('README2.txt', Node.FILE, Changeset.COPY,
diff --git a/trac/versioncontrol/web_ui/changeset.py b/trac/versioncontrol/web_ui/changeset.py
--- a/trac/versioncontrol/web_ui/changeset.py
+++ b/trac/versioncontrol/web_ui/changeset.py
@@ -18,7 +18,6 @@
 #         Christopher Lenz <cmlenz@gmx.de>
 #         Christian Boos <cboos@neuf.fr>
 
-from datetime import datetime
 from itertools import groupby
 import os
 import posixpath
@@ -36,7 +35,7 @@
 from trac.timeline.api import ITimelineEventProvider
 from trac.util import embedded_numbers, content_disposition
 from trac.util.compat import any
-from trac.util.datefmt import pretty_timedelta, utc
+from trac.util.datefmt import from_utimestamp, pretty_timedelta
 from trac.util.text import exception_to_unicode, unicode_urlencode, \
                            shorten_line, CRLF
 from trac.util.translation import _
@@ -992,8 +991,7 @@
                 continue
             yield (req.href.changeset(rev),
                    '[%s]: %s' % (rev, shorten_line(log)),
-                   datetime.fromtimestamp(ts, utc), author,
-                   shorten_result(log, terms))
+                   from_utimestamp(ts), author, shorten_result(log, terms))
 
 
 class AnyDiffModule(Component):
diff --git a/trac/web/chrome.py b/trac/web/chrome.py
--- a/trac/web/chrome.py
+++ b/trac/web/chrome.py
@@ -65,7 +65,7 @@
                            shorten_line, unicode_quote_plus, to_unicode, \
                            javascript_quote, exception_to_unicode
 from trac.util.datefmt import pretty_timedelta, format_datetime, format_date, \
-                              format_time, http_date, utc
+                              format_time, from_utimestamp, http_date, utc
 from trac.util.translation import _
 from trac.web.api import IRequestHandler, ITemplateStreamFilter, HTTPNotFound
 from trac.web.href import Href
@@ -751,6 +751,7 @@
             'format_time': partial(format_time, tzinfo=tzinfo),
             'fromtimestamp': partial(datetime.datetime.fromtimestamp,
                                      tz=tzinfo),
+            'from_utimestamp': from_utimestamp,
 
             # Wiki-formatting functions
             'wiki_to': partial(format_to, self.env),
diff --git a/trac/web/tests/session.py b/trac/web/tests/session.py
--- a/trac/web/tests/session.py
+++ b/trac/web/tests/session.py
@@ -166,7 +166,7 @@
                        (0,))
         cursor.execute("INSERT INTO session "
                        "VALUES ('987654', 0, %s)",
-                       (time.time() - PURGE_AGE - 3600,))
+                       (int(time.time() - PURGE_AGE - 3600),))
         cursor.execute("INSERT INTO session_attribute VALUES "
                        "('987654', 0, 'foo', 'bar')")
         
diff --git a/trac/wiki/admin.py b/trac/wiki/admin.py
--- a/trac/wiki/admin.py
+++ b/trac/wiki/admin.py
@@ -15,7 +15,6 @@
 import os.path
 import pkg_resources
 import sys
-import time
 
 from trac.admin import *
 from trac.core import *
@@ -23,7 +22,8 @@
 from trac.wiki.api import WikiSystem
 from trac.util import read_file
 from trac.util.compat import any
-from trac.util.datefmt import format_datetime, utc
+from trac.util.datefmt import format_datetime, from_utimestamp, \
+                              to_utimestamp, utc
 from trac.util.text import to_unicode, unicode_quote, unicode_unquote, \
                            print_table, printout
 from trac.util.translation import _
@@ -144,7 +144,8 @@
                            "SELECT 1+COALESCE(max(version),0),%s,%s,"
                            "       'trac','127.0.0.1',%s FROM wiki "
                            "WHERE name=%s",
-                           (title, int(time.time()), data, title))
+                           (title, to_utimestamp(datetime.now(utc)), data,
+                            title))
         if not old:
             WikiSystem(self.env).pages.invalidate(db)
         if handle_ta:
@@ -190,7 +191,7 @@
         cursor.execute("SELECT name, max(version), max(time) "
                        "FROM wiki GROUP BY name ORDER BY name")
         print_table([(r[0], int(r[1]),
-                      format_datetime(datetime.fromtimestamp(r[2], utc),
+                      format_datetime(from_utimestamp(r[2]),
                                       console_datetime_format))
                      for r in cursor],
                     [_('Title'), _('Edits'), _('Modified')])
diff --git a/trac/wiki/macros.py b/trac/wiki/macros.py
--- a/trac/wiki/macros.py
+++ b/trac/wiki/macros.py
@@ -14,7 +14,6 @@
 #
 # Author: Christopher Lenz <cmlenz@gmx.de>
 
-from datetime import datetime
 from itertools import groupby
 import inspect
 import os
@@ -27,7 +26,7 @@
 from trac.core import *
 from trac.resource import Resource, get_resource_url, get_resource_summary
 from trac.util.compat import rpartition
-from trac.util.datefmt import format_date, utc
+from trac.util.datefmt import format_date, from_utimestamp
 from trac.util.html import escape
 from trac.util.presentation import separated
 from trac.util.text import unquote, to_unicode
@@ -225,8 +224,7 @@
         for name, version, ts in cursor:
             if not 'WIKI_VIEW' in formatter.perm('wiki', name, version):
                 continue
-            time = datetime.fromtimestamp(ts, utc)
-            date = format_date(time)
+            date = format_date(from_utimestamp(ts))
             if date != prevdate:
                 prevdate = date
                 entries_per_date.append((date, []))
diff --git a/trac/wiki/model.py b/trac/wiki/model.py
--- a/trac/wiki/model.py
+++ b/trac/wiki/model.py
@@ -20,7 +20,7 @@
 
 from trac.core import *
 from trac.resource import Resource
-from trac.util.datefmt import utc, to_timestamp
+from trac.util.datefmt import from_utimestamp, to_utimestamp, utc
 from trac.util.translation import _
 from trac.wiki.api import WikiSystem
 
@@ -69,7 +69,7 @@
             version, time, author, text, comment, readonly = row
             self.version = int(version)
             self.author = author
-            self.time = datetime.fromtimestamp(time, utc)
+            self.time = from_utimestamp(time)
             self.text = text
             self.comment = comment
             self.readonly = readonly and int(readonly) or 0
@@ -138,7 +138,7 @@
             cursor.execute("INSERT INTO wiki (name,version,time,author,ipnr,"
                            "text,comment,readonly) VALUES (%s,%s,%s,%s,%s,%s,"
                            "%s,%s)", (self.name, self.version + 1,
-                                      to_timestamp(t), author, remote_addr,
+                                      to_utimestamp(t), author, remote_addr,
                                       self.text, comment, self.readonly))
             self.version += 1
             self.resource = self.resource(version=self.version)
@@ -178,5 +178,4 @@
                        "WHERE name=%s AND version<=%s "
                        "ORDER BY version DESC", (self.name, self.version))
         for version, ts, author, comment, ipnr in cursor:
-            time = datetime.fromtimestamp(ts, utc)
-            yield version, time, author, comment, ipnr
+            yield version, from_utimestamp(ts), author, comment, ipnr
diff --git a/trac/wiki/tests/model.py b/trac/wiki/tests/model.py
--- a/trac/wiki/tests/model.py
+++ b/trac/wiki/tests/model.py
@@ -3,7 +3,7 @@
 
 from trac.core import *
 from trac.test import EnvironmentStub
-from trac.util.datefmt import utc, to_timestamp
+from trac.util.datefmt import utc, to_utimestamp
 from trac.wiki import WikiPage, IWikiChangeListener
 
 
@@ -52,7 +52,7 @@
         t = datetime(2001, 1, 1, 1, 1, 1, 0, utc)
         cursor = self.db.cursor()
         cursor.execute("INSERT INTO wiki VALUES(%s,%s,%s,%s,%s,%s,%s,%s)",
-                       ('TestPage', 1, to_timestamp(t), 'joe', '::1',
+                       ('TestPage', 1, to_utimestamp(t), 'joe', '::1',
                         'Bla bla', 'Testing', 0))
 
         page = WikiPage(self.env, 'TestPage')
@@ -91,7 +91,7 @@
         cursor = self.db.cursor()
         cursor.execute("SELECT version,time,author,ipnr,text,comment,"
                        "readonly FROM wiki WHERE name=%s", ('TestPage',))
-        self.assertEqual((1, to_timestamp(t), 'joe', '::1', 'Bla bla',
+        self.assertEqual((1, to_utimestamp(t), 'joe', '::1', 'Bla bla',
                           'Testing', 0),
                          cursor.fetchone())
 
@@ -103,7 +103,7 @@
         t = datetime(2001, 1, 1, 1, 1, 1, 0, utc)
         t2 = datetime(2002, 1, 1, 1, 1, 1, 0, utc)
         cursor.execute("INSERT INTO wiki VALUES(%s,%s,%s,%s,%s,%s,%s,%s)",
-                       ('TestPage', 1, to_timestamp(t), 'joe', '::1',
+                       ('TestPage', 1, to_utimestamp(t), 'joe', '::1',
                         'Bla bla', 'Testing', 0))
 
         page = WikiPage(self.env, 'TestPage')
@@ -119,10 +119,10 @@
 
         cursor.execute("SELECT version,time,author,ipnr,text,comment,"
                        "readonly FROM wiki WHERE name=%s", ('TestPage',))
-        self.assertEqual((1, to_timestamp(t), 'joe', '::1', 'Bla bla',
+        self.assertEqual((1, to_utimestamp(t), 'joe', '::1', 'Bla bla',
                           'Testing', 0),
                          cursor.fetchone())
-        self.assertEqual((2, to_timestamp(t2), 'kate', '192.168.0.101', 'Bla',
+        self.assertEqual((2, to_utimestamp(t2), 'kate', '192.168.0.101', 'Bla',
                           'Changing', 0), cursor.fetchone())
 
         listener = TestWikiChangeListener(self.env)
diff --git a/trac/wiki/web_ui.py b/trac/wiki/web_ui.py
--- a/trac/wiki/web_ui.py
+++ b/trac/wiki/web_ui.py
@@ -16,7 +16,6 @@
 # Author: Jonas Borgström <jonas@edgewall.com>
 #         Christopher Lenz <cmlenz@gmx.de>
 
-from datetime import datetime
 import pkg_resources
 import re
 
@@ -31,7 +30,7 @@
 from trac.search import ISearchSource, search_to_sql, shorten_result
 from trac.timeline.api import ITimelineEventProvider
 from trac.util import get_reporter_id
-from trac.util.datefmt import to_timestamp, utc
+from trac.util.datefmt import from_utimestamp, to_utimestamp
 from trac.util.text import shorten_line
 from trac.util.translation import _
 from trac.versioncontrol.diff import get_diff_options, diff_blocks
@@ -630,12 +629,12 @@
             cursor = db.cursor()
             cursor.execute("SELECT time,name,comment,author,version "
                            "FROM wiki WHERE time>=%s AND time<=%s",
-                           (to_timestamp(start), to_timestamp(stop)))
+                           (to_utimestamp(start), to_utimestamp(stop)))
             for ts, name, comment, author, version in cursor:
                 wiki_page = wiki_realm(id=name, version=version)
                 if 'WIKI_VIEW' not in req.perm(wiki_page):
                     continue
-                yield ('wiki', datetime.fromtimestamp(ts, utc), author,
+                yield ('wiki', from_utimestamp(ts), author,
                        (wiki_page, comment))
 
             # Attachments
@@ -686,7 +685,7 @@
             if 'WIKI_VIEW' in req.perm(page):
                 yield (get_resource_url(self.env, page, req.href),
                        '%s: %s' % (name, shorten_line(text)),
-                       datetime.fromtimestamp(ts, utc), author,
+                       from_utimestamp(ts), author,
                        shorten_result(text, terms))
         
         # Attachments

