Edgewall Software

Ticket #6466: 6466-alter-table-r8222.patch

File 6466-alter-table-r8222.patch, 70.1 KB (added by rblank, 3 years ago)

Use ALTER TABLE for the upgrade.

  • trac/attachment.py

    diff --git a/trac/attachment.py b/trac/attachment.py
    a b  
    2121import re 
    2222import shutil 
    2323import sys 
    24 import time 
    2524import unicodedata 
    2625 
    2726from genshi.builder import tag 
     
    3635from trac.resource import * 
    3736from trac.search import search_to_sql, shorten_result 
    3837from trac.util import get_reporter_id, create_unique_file 
    39 from trac.util.datefmt import format_datetime, to_timestamp, utc 
     38from trac.util.datefmt import format_datetime, from_utimestamp, \ 
     39                              to_datetime, to_utimestamp, utc 
    4040from trac.util.text import exception_to_unicode, pretty_size, print_table, \ 
    4141                           unicode_quote, unicode_unquote 
    4242from trac.util.translation import _ 
     
    150150        self.filename = row[0] 
    151151        self.description = row[1] 
    152152        self.size = row[2] and int(row[2]) or 0 
    153         time = row[3] and int(row[3]) or 0 
    154         self.date = datetime.fromtimestamp(time, utc) 
     153        self.date = from_utimestamp(row[3]) 
    155154        self.author = row[4] 
    156155        self.ipnr = row[5] 
    157156 
     
    199198 
    200199 
    201200    def insert(self, filename, fileobj, size, t=None, db=None): 
    202         # FIXME: `t` should probably be switched to `datetime` too 
    203201        if not db: 
    204202            db = self.env.get_db_cnx() 
    205203            handle_ta = True 
     
    207205            handle_ta = False 
    208206 
    209207        self.size = size and int(size) or 0 
    210         timestamp = int(t or time.time()) 
    211         self.date = datetime.fromtimestamp(timestamp, utc) 
     208        if t is None: 
     209            t = datetime.now(utc) 
     210        elif not isinstance(t, datetime): # Compatibility with 0.11 
     211            t = to_datetime(t, utc) 
     212        self.date = t 
    212213 
    213214        # Make sure the path to the attachment is inside the environment 
    214215        # attachments directory 
     
    232233            cursor.execute("INSERT INTO attachment " 
    233234                           "VALUES (%s,%s,%s,%s,%s,%s,%s,%s)", 
    234235                           (self.parent_realm, self.parent_id, filename, 
    235                             self.size, timestamp, self.description, 
     236                            self.size, to_utimestamp(t), self.description, 
    236237                            self.author, self.ipnr)) 
    237238            shutil.copyfileobj(fileobj, targetfile) 
    238239            self.resource.id = self.filename = filename 
     
    265266            attachment.filename = filename 
    266267            attachment.description = description 
    267268            attachment.size = size and int(size) or 0 
    268             time = time and int(time) or 0 
    269             attachment.date = datetime.fromtimestamp(time, utc) 
     269            attachment.date = from_utimestamp(time or 0) 
    270270            attachment.author = author 
    271271            attachment.ipnr = ipnr 
    272272            yield attachment 
     
    452452                       "  FROM attachment " 
    453453                       "  WHERE time > %s AND time < %s " 
    454454                       "        AND type = %s", 
    455                        (to_timestamp(start), to_timestamp(stop), realm)) 
     455                       (to_utimestamp(start), to_utimestamp(stop), realm)) 
    456456        for realm, id, filename, ts, description, author in cursor: 
    457             time = datetime.fromtimestamp(ts, utc) 
     457            time = from_utimestamp(ts) 
    458458            yield ('created', realm, id, filename, time, description, author) 
    459459 
    460460    def get_timeline_events(self, req, resource_realm, start, stop): 
     
    502502            if 'ATTACHMENT_VIEW' in req.perm(attachment): 
    503503                yield (get_resource_url(self.env, attachment, req.href), 
    504504                       get_resource_shortname(self.env, attachment), 
    505                        datetime.fromtimestamp(time, utc), author, 
     505                       from_utimestamp(time), author, 
    506506                       shorten_result(desc, terms)) 
    507507     
    508508    # IResourceManager methods 
  • trac/db/api.py

    diff --git a/trac/db/api.py b/trac/db/api.py
    a b  
    8383        self._cnx_pool = None 
    8484 
    8585    def init_db(self): 
    86         connector, args = self._get_connector() 
     86        connector, args = self.get_connector() 
    8787        connector.init_db(**args) 
    8888 
    8989    def get_connection(self): 
    9090        if not self._cnx_pool: 
    91             connector, args = self._get_connector() 
     91            connector, args = self.get_connector() 
    9292            self._cnx_pool = ConnectionPool(5, connector, **args) 
    9393        return self._cnx_pool.get_cnx(self.timeout or None) 
    9494 
     
    104104        @param dest: base filename to write to. 
    105105        Returns the file actually written. 
    106106        """ 
    107         connector, args = self._get_connector() 
     107        connector, args = self.get_connector() 
    108108        if not dest: 
    109109            backup_dir = self.backup_dir 
    110110            if backup_dir[0] != "/": 
     
    120120            os.makedirs(backup_dir) 
    121121        return connector.backup(dest) 
    122122 
    123     def _get_connector(self): ### FIXME: Make it public? 
     123    def get_connector(self): 
    124124        scheme, args = _parse_db_str(self.connection_uri) 
    125125        candidates = [ 
    126126            (priority, connector) 
     
    147147            args['log'] = self.log 
    148148        return connector, args 
    149149 
     150    _get_connector = get_connector  # For 0.11 compatibility 
     151 
    150152 
    151153def _parse_db_str(db_str): 
    152154    scheme, rest = db_str.split(':', 1) 
  • trac/db/mysql_backend.py

    diff --git a/trac/db/mysql_backend.py b/trac/db/mysql_backend.py
    a b  
    5252except ImportError: 
    5353    has_mysqldb = False 
    5454 
     55# Mapping from "abstract" SQL types to DB-specific types 
     56_type_map = { 
     57    'int64': 'bigint', 
     58} 
     59 
    5560 
    5661class MySQLConnector(Component): 
    5762    """MySQL database support for version 4.1 and greater. 
     
    133138        coldefs = [] 
    134139        for column in table.columns: 
    135140            ctype = column.type 
     141            ctype = _type_map.get(ctype, ctype) 
    136142            if column.auto_increment: 
    137143                ctype = 'INT UNSIGNED NOT NULL AUTO_INCREMENT' 
    138144                # Override the column type, as a text field cannot 
     
    151157                  '_'.join(index.columns), table.name, 
    152158                  self._collist(table, index.columns)) 
    153159 
     160    def alter_column_types(self, table, columns): 
     161        """Yield SQL statements altering the type of one or more columns of 
     162        a table. 
     163         
     164        Type changes are specified as a `columns` dict mapping column names 
     165        to `(from, to)` SQL type tuples. 
     166        """ 
     167        alterations = [] 
     168        for name, (from_, to) in sorted(columns.iteritems()): 
     169            to = _type_map.get(to, to) 
     170            if to != _type_map.get(from_, from_): 
     171                alterations.append((name, to)) 
     172        if alterations: 
     173            yield "ALTER TABLE %s %s" % (table, 
     174                ', '.join("MODIFY %s %s" % each 
     175                          for each in alterations)) 
     176 
    154177    def backup(self, dest_file): 
    155178        try: 
    156179            from subprocess import Popen, PIPE 
     
    238261 
    239262    def cursor(self): 
    240263        return MySQLUnicodeCursor(self.cnx) 
     264 
     265    def alter_column_types(cursor, table, columns): 
     266        """Alter the type of one or more columns of a table. 
     267         
     268        Type changes are specified as a `columns` dict mapping column names 
     269        to `(from_type, to_type)` tuples. 
     270        """ 
     271        for name, (from_type, to_type) in columns.iteritems(): 
     272            if (from_type, to_type) == ('int', 'int64'): 
     273                pass 
     274            else: 
     275                raise NotImplementedError('Conversion from %s to %s is not ' 
     276                                          'implemented') 
  • trac/db/postgres_backend.py

    diff --git a/trac/db/postgres_backend.py b/trac/db/postgres_backend.py
    a b  
    4545 
    4646_like_escape_re = re.compile(r'([/_%])') 
    4747 
     48# Mapping from "abstract" SQL types to DB-specific types 
     49_type_map = { 
     50    'int64': 'bigint', 
     51} 
     52 
    4853 
    4954class PostgreSQLConnector(Component): 
    5055    """PostgreSQL database support.""" 
     
    9297        coldefs = [] 
    9398        for column in table.columns: 
    9499            ctype = column.type 
     100            ctype = _type_map.get(ctype, ctype) 
    95101            if column.auto_increment: 
    96102                ctype = 'SERIAL' 
    97             if len(table.key) == 1 and column.name in table.key: 
     103            elif len(table.key) == 1 and column.name in table.key: 
    98104                ctype += ' PRIMARY KEY' 
    99105            coldefs.append('    "%s" %s' % (column.name, ctype)) 
    100106        if len(table.key) > 1: 
     
    109115                     '_'.join(index.columns), table.name, 
    110116                     '","'.join(index.columns)) 
    111117 
     118    def alter_column_types(self, table, columns): 
     119        """Yield SQL statements altering the type of one or more columns of 
     120        a table. 
     121         
     122        Type changes are specified as a `columns` dict mapping column names 
     123        to `(from, to)` SQL type tuples. 
     124        """ 
     125        alterations = [] 
     126        for name, (from_, to) in sorted(columns.iteritems()): 
     127            to = _type_map.get(to, to) 
     128            if to != _type_map.get(from_, from_): 
     129                alterations.append((name, to)) 
     130        if alterations: 
     131            yield "ALTER TABLE %s %s" % (table, 
     132                ', '.join("ALTER COLUMN %s TYPE %s" % each 
     133                          for each in alterations)) 
     134 
    112135    def backup(self, dest_file): 
    113136        try: 
    114137            from subprocess import Popen, PIPE 
  • trac/db/sqlite_backend.py

    diff --git a/trac/db/sqlite_backend.py b/trac/db/sqlite_backend.py
    a b  
    107107                    return 
    108108                yield row 
    109109 
     110# Mapping from "abstract" SQL types to DB-specific types 
     111_type_map = { 
     112    'int': 'integer', 
     113    'int64': 'integer', 
     114} 
     115 
    110116 
    111117def _to_sql(table): 
    112118    sql = ["CREATE TABLE %s (" % table.name] 
    113119    coldefs = [] 
    114120    for column in table.columns: 
    115121        ctype = column.type.lower() 
     122        ctype = _type_map.get(ctype, ctype) 
    116123        if column.auto_increment: 
    117124            ctype = "integer PRIMARY KEY" 
    118125        elif len(table.key) == 1 and column.name in table.key: 
    119126            ctype += " PRIMARY KEY" 
    120         elif ctype == "int": 
    121             ctype = "integer" 
    122127        coldefs.append("    %s %s" % (column.name, ctype)) 
    123128    if len(table.key) > 1: 
    124129        coldefs.append("    UNIQUE (%s)" % ','.join(table.key)) 
     
    175180    def to_sql(self, table): 
    176181        return _to_sql(table) 
    177182 
     183    def alter_column_types(self, table, columns): 
     184        """Yield SQL statements altering the type of one or more columns of 
     185        a table. 
     186         
     187        Type changes are specified as a `columns` dict mapping column names 
     188        to `(from, to)` SQL type tuples. 
     189        """ 
     190        for name, (from_, to) in sorted(columns.iteritems()): 
     191            if _type_map.get(to, to) != _type_map.get(from_, from_): 
     192                raise NotImplementedError('Conversion from %s to %s is not ' 
     193                                          'implemented' % (from_, to)) 
     194        return () 
     195 
    178196    def backup(self, dest_file): 
    179197        """Simple SQLite-specific backup of the database. 
    180198 
     
    188206            raise TracError("Backup attempt failed") 
    189207        return dest_file 
    190208 
     209 
    191210class SQLiteConnection(ConnectionWrapper): 
    192211    """Connection wrapper for SQLite.""" 
    193212 
  • trac/db/tests/__init__.py

    diff --git a/trac/db/tests/__init__.py b/trac/db/tests/__init__.py
    a b  
    11import unittest 
    22 
    3 from trac.db.tests import api 
    4 from trac.db.tests import postgres_test 
     3from trac.db.tests import api, mysql_test, postgres_test 
    54 
    65from trac.db.tests.functional import functionalSuite 
    76 
     
    98 
    109    suite = unittest.TestSuite() 
    1110    suite.addTest(api.suite()) 
     11    suite.addTest(mysql_test.suite()) 
    1212    suite.addTest(postgres_test.suite()) 
    1313    return suite 
    1414 
  • new file trac/db/tests/mysql_test.py

    diff --git a/trac/db/tests/mysql_test.py b/trac/db/tests/mysql_test.py
    new file mode 100644
    - +  
     1# -*- coding: utf-8 -*- 
     2# 
     3# Copyright (C) 2009 Edgewall Software 
     4# All rights reserved. 
     5# 
     6# This software is licensed as described in the file COPYING, which 
     7# you should have received as part of this distribution. The terms 
     8# are also available at http://trac.edgewall.org/wiki/TracLicense. 
     9# 
     10# This software consists of voluntary contributions made by many 
     11# individuals. For the exact contribution history, see the revision 
     12# history and logs, available at http://trac.edgewall.org/log/. 
     13 
     14import unittest 
     15 
     16from trac.db.mysql_backend import MySQLConnector 
     17from trac.test import EnvironmentStub 
     18 
     19 
     20class MySQLTableAlterationSQLTest(unittest.TestCase): 
     21    def setUp(self): 
     22        self.env = EnvironmentStub() 
     23     
     24    def test_alter_column_types(self): 
     25        connector = MySQLConnector(self.env) 
     26        sql = connector.alter_column_types('milestone', 
     27                                           {'due': ('int', 'int64'), 
     28                                            'completed': ('int', 'int64')}) 
     29        sql = list(sql) 
     30        self.assertEqual([ 
     31            "ALTER TABLE milestone " 
     32                "MODIFY completed bigint, " 
     33                "MODIFY due bigint", 
     34            ], sql) 
     35 
     36    def test_alter_column_types_same(self): 
     37        connector = MySQLConnector(self.env) 
     38        sql = connector.alter_column_types('milestone', 
     39                                           {'due': ('int', 'int'), 
     40                                            'completed': ('int', 'int64')}) 
     41        sql = list(sql) 
     42        self.assertEqual([ 
     43            "ALTER TABLE milestone " 
     44                "MODIFY completed bigint", 
     45            ], sql) 
     46 
     47    def test_alter_column_types_none(self): 
     48        connector = MySQLConnector(self.env) 
     49        sql = connector.alter_column_types('milestone', 
     50                                           {'due': ('int', 'int')}) 
     51        self.assertEqual([], list(sql)) 
     52 
     53 
     54def suite(): 
     55    suite = unittest.TestSuite() 
     56    suite.addTest(unittest.makeSuite(MySQLTableAlterationSQLTest, 'test')) 
     57    return suite 
     58 
     59 
     60if __name__ == '__main__': 
     61    unittest.main(defaultTest='suite') 
  • trac/db/tests/postgres_test.py

    diff --git a/trac/db/tests/postgres_test.py b/trac/db/tests/postgres_test.py
    a b  
    1111class PostgresTableCreationSQLTest(unittest.TestCase): 
    1212    def setUp(self): 
    1313        self.env = EnvironmentStub() 
    14         self.db = self.env.get_db_cnx() 
    1514     
    1615    def _unroll_generator(self, generator): 
    1716        items = [] 
     
    8281        self.assertEqual(index_sql, sql_commands[1]) 
    8382 
    8483 
     84class PostgresTableAlterationSQLTest(unittest.TestCase): 
     85    def setUp(self): 
     86        self.env = EnvironmentStub() 
     87     
     88    def test_alter_column_types(self): 
     89        connector = PostgreSQLConnector(self.env) 
     90        sql = connector.alter_column_types('milestone', 
     91                                           {'due': ('int', 'int64'), 
     92                                            'completed': ('int', 'int64')}) 
     93        sql = list(sql) 
     94        self.assertEqual([ 
     95            "ALTER TABLE milestone " 
     96                "ALTER COLUMN completed TYPE bigint, " 
     97                "ALTER COLUMN due TYPE bigint", 
     98            ], sql) 
     99 
     100    def test_alter_column_types_same(self): 
     101        connector = PostgreSQLConnector(self.env) 
     102        sql = connector.alter_column_types('milestone', 
     103                                           {'due': ('int', 'int'), 
     104                                            'completed': ('int', 'int64')}) 
     105        sql = list(sql) 
     106        self.assertEqual([ 
     107            "ALTER TABLE milestone " 
     108                "ALTER COLUMN completed TYPE bigint", 
     109            ], sql) 
     110 
     111    def test_alter_column_types_none(self): 
     112        connector = PostgreSQLConnector(self.env) 
     113        sql = connector.alter_column_types('milestone', 
     114                                           {'due': ('int', 'int')}) 
     115        self.assertEqual([], list(sql)) 
     116 
     117 
    85118def suite(): 
    86     return unittest.makeSuite(PostgresTableCreationSQLTest, 'test') 
     119    suite = unittest.TestSuite() 
     120    suite.addTest(unittest.makeSuite(PostgresTableCreationSQLTest, 'test')) 
     121    suite.addTest(unittest.makeSuite(PostgresTableAlterationSQLTest, 'test')) 
     122    return suite 
     123 
    87124 
    88125if __name__ == '__main__': 
    89126    unittest.main(defaultTest='suite') 
  • trac/db_default.py

    diff --git a/trac/db_default.py b/trac/db_default.py
    a b  
    1717from trac.db import Table, Column, Index 
    1818 
    1919# Database version identifier. Used for automatic upgrades. 
    20 db_version = 22 
     20db_version = 23 
    2121 
    2222def __mkreports(reports): 
    2323    """Utility function used to create report data in same syntax as the 
     
    6767        Column('id'), 
    6868        Column('filename'), 
    6969        Column('size', type='int'), 
    70         Column('time', type='int'), 
     70        Column('time', type='int64'), 
    7171        Column('description'), 
    7272        Column('author'), 
    7373        Column('ipnr')], 
     
    7676    Table('wiki', key=('name', 'version'))[ 
    7777        Column('name'), 
    7878        Column('version', type='int'), 
    79         Column('time', type='int'), 
     79        Column('time', type='int64'), 
    8080        Column('author'), 
    8181        Column('ipnr'), 
    8282        Column('text'), 
     
    8787    # Version control cache 
    8888    Table('revision', key='rev')[ 
    8989        Column('rev'), 
    90         Column('time', type='int'), 
     90        Column('time', type='int64'), 
    9191        Column('author'), 
    9292        Column('message'), 
    9393        Index(['time'])], 
     
    104104    Table('ticket', key='id')[ 
    105105        Column('id', auto_increment=True), 
    106106        Column('type'), 
    107         Column('time', type='int'), 
    108         Column('changetime', type='int'), 
     107        Column('time', type='int64'), 
     108        Column('changetime', type='int64'), 
    109109        Column('component'), 
    110110        Column('severity'), 
    111111        Column('priority'), 
     
    123123        Index(['status'])],     
    124124    Table('ticket_change', key=('ticket', 'time', 'field'))[ 
    125125        Column('ticket', type='int'), 
    126         Column('time', type='int'), 
     126        Column('time', type='int64'), 
    127127        Column('author'), 
    128128        Column('field'), 
    129129        Column('oldvalue'), 
     
    144144        Column('description')], 
    145145    Table('milestone', key='name')[ 
    146146        Column('name'), 
    147         Column('due', type='int'), 
    148         Column('completed', type='int'), 
     147        Column('due', type='int64'), 
     148        Column('completed', type='int64'), 
    149149        Column('description')], 
    150150    Table('version', key='name')[ 
    151151        Column('name'), 
    152         Column('time', type='int'), 
     152        Column('time', type='int64'), 
    153153        Column('description')], 
    154154 
    155155    # Report system 
  • trac/ticket/model.py

    diff --git a/trac/ticket/model.py b/trac/ticket/model.py
    a b  
    2626from trac.ticket.api import TicketSystem 
    2727from trac.util import embedded_numbers, partition 
    2828from trac.util.text import empty 
    29 from trac.util.datefmt import utc, utcmax, to_timestamp 
     29from trac.util.datefmt import from_utimestamp, to_utimestamp, utc, utcmax 
    3030from trac.util.translation import _ 
    3131 
    3232__all__ = ['Ticket', 'Type', 'Status', 'Resolution', 'Priority', 'Severity', 
     
    111111        for i, field in enumerate(std_fields): 
    112112            value = row[i] 
    113113            if field in self.time_fields: 
    114                 self.values[field] = datetime.fromtimestamp(value or 0, utc) 
     114                self.values[field] = from_utimestamp(value) 
    115115            elif value is None: 
    116116                self.values[field] = empty 
    117117            else: 
     
    198198        values = dict(self.values) 
    199199        for field in self.time_fields: 
    200200            if field in values: 
    201                 values[field] = to_timestamp(values[field]) 
     201                values[field] = to_utimestamp(values[field]) 
    202202         
    203203        # Insert ticket record 
    204204        std_fields = [] 
     
    248248        cursor = db.cursor() 
    249249        if when is None: 
    250250            when = datetime.now(utc) 
    251         when_ts = to_timestamp(when) 
     251        when_ts = to_utimestamp(when) 
    252252 
    253253        if 'component' in self.values: 
    254254            # If the component is changed on a 'new' ticket then owner field 
     
    328328        db = self._get_db(db) 
    329329        cursor = db.cursor() 
    330330        sid = str(self.id) 
    331         when_ts = when and to_timestamp(when) or 0 
     331        when_ts = to_utimestamp(when) 
    332332        if when_ts: 
    333333            cursor.execute("SELECT time,author,field,oldvalue,newvalue," 
    334334                           "1 AS permanent FROM ticket_change " 
     
    356356                           (self.id, sid, sid)) 
    357357        log = [] 
    358358        for t, author, field, oldvalue, newvalue, permanent in cursor: 
    359             log.append((datetime.fromtimestamp(int(t), utc), author, field, 
    360                        oldvalue or '', newvalue or '', permanent)) 
     359            log.append((from_utimestamp(t), author, field, 
     360                        oldvalue or '', newvalue or '', permanent)) 
    361361        return log 
    362362 
    363363    def delete(self, db=None): 
     
    389389                           "WHERE ticket=%s AND time=%s", 
    390390                           (self.id, ts)) 
    391391            fields = {} 
    392             change = {'date': datetime.fromtimestamp(int(ts), utc), 
     392            change = {'date': from_utimestamp(ts), 
    393393                      'author': author, 'fields': fields} 
    394394            for field, author, old, new in cursor: 
    395395                fields[field] = {'author': author, 'old': old, 'new': new} 
     
    400400        scnum = str(cnum) 
    401401        if when is None: 
    402402            when = datetime.now(utc) 
    403         when_ts = to_timestamp(when) 
     403        when_ts = to_utimestamp(when) 
    404404         
    405405        db, handle_ta = self._get_db_for_write(db) 
    406406        like = db.like() 
     
    445445                           (self.id, ts0, db.like_escape('_comment') + '%')) 
    446446            for field, author, comment, ts in cursor: 
    447447                rev = int(field[8:]) 
    448                 history.append((rev, datetime.fromtimestamp(int(ts0), utc), 
    449                                 author0, comment)) 
     448                history.append((rev, from_utimestamp(long(ts0)), author0, 
     449                                comment)) 
    450450                ts0, author0 = ts, author 
    451451            history.sort() 
    452452            rev = history and (history[-1][0] + 1) or 0 
    453             history.append((rev, datetime.fromtimestamp(int(ts), utc), 
    454                             author, last_comment)) 
     453            history.append((rev, from_utimestamp(long(ts)), author, 
     454                            last_comment)) 
    455455        return history 
    456456 
    457457 
     
    758758    def _from_database(self, row): 
    759759        name, due, completed, description = row 
    760760        self.name = self._old_name = name 
    761         self.due = due and datetime.fromtimestamp(int(due), utc) or None 
    762         self.completed = completed and \ 
    763                          datetime.fromtimestamp(int(completed), utc) or None 
     761        self.due = due and from_utimestamp(due) or None 
     762        self.completed = completed and from_utimestamp(completed) or None 
    764763        self.description = description or '' 
    765764 
    766765    def delete(self, retarget_to=None, author=None, db=None): 
     
    803802        self.env.log.debug("Creating new milestone '%s'" % self.name) 
    804803        cursor.execute("INSERT INTO milestone (name,due,completed,description) " 
    805804                       "VALUES (%s,%s,%s,%s)", 
    806                        (self.name, to_timestamp(self.due), to_timestamp(self.completed), 
    807                         self.description)) 
     805                       (self.name, to_utimestamp(self.due), 
     806                        to_utimestamp(self.completed), self.description)) 
    808807        self._old_name = self.name 
    809808        TicketSystem(self.env).reset_ticket_fields(db) 
    810809 
     
    825824        self.env.log.info('Updating milestone "%s"' % self.name) 
    826825        cursor.execute("UPDATE milestone SET name=%s,due=%s," 
    827826                       "completed=%s,description=%s WHERE name=%s", 
    828                        (self.name, to_timestamp(self.due), to_timestamp(self.completed), 
    829                         self.description, 
     827                       (self.name, to_utimestamp(self.due), 
     828                        to_utimestamp(self.completed), self.description, 
    830829                        self._old_name)) 
    831830        self.env.log.info('Updating milestone field of all tickets ' 
    832831                          'associated with milestone "%s"' % self.name) 
     
    892891                raise ResourceNotFound(_('Version %(name)s does not exist.', 
    893892                                         name=name)) 
    894893            self.name = self._old_name = name 
    895             self.time = row[0] and datetime.fromtimestamp(int(row[0]), utc) or None 
     894            self.time = row[0] and from_utimestamp(row[0]) or None 
    896895            self.description = row[1] or '' 
    897896        else: 
    898897            self.name = self._old_name = None 
     
    933932        self.env.log.debug("Creating new version '%s'" % self.name) 
    934933        cursor.execute("INSERT INTO version (name,time,description) " 
    935934                       "VALUES (%s,%s,%s)", 
    936                        (self.name, to_timestamp(self.time), self.description)) 
     935                       (self.name, to_utimestamp(self.time), self.description)) 
    937936        self._old_name = self.name 
    938937        TicketSystem(self.env).reset_ticket_fields(db) 
    939938 
     
    955954        self.env.log.info('Updating version "%s"' % self.name) 
    956955        cursor.execute("UPDATE version SET name=%s,time=%s,description=%s " 
    957956                       "WHERE name=%s", 
    958                        (self.name, to_timestamp(self.time), self.description, 
     957                       (self.name, to_utimestamp(self.time), self.description, 
    959958                        self._old_name)) 
    960959        if self.name != self._old_name: 
    961960            # Update tickets 
     
    977976        for name, time, description in cursor: 
    978977            version = cls(env) 
    979978            version.name = version._old_name = name 
    980             version.time = time and datetime.fromtimestamp(int(time), utc) or None 
     979            version.time = time and from_utimestamp(time) or None 
    981980            version.description = description or '' 
    982981            versions.append(version) 
    983982        def version_order(v): 
  • trac/ticket/query.py

    diff --git a/trac/ticket/query.py b/trac/ticket/query.py
    a b  
    3131from trac.resource import Resource 
    3232from trac.ticket.api import TicketSystem 
    3333from trac.util import Ranges 
    34 from trac.util.datefmt import format_datetime, parse_date, to_timestamp, utc 
     34from trac.util.datefmt import format_datetime, from_utimestamp, parse_date, \ 
     35                              to_timestamp, to_utimestamp, utc 
    3536from trac.util.presentation import Paginator 
    3637from trac.util.text import empty, shorten_line, unicode_unquote 
    3738from trac.util.translation import _, tag_ 
     
    331332                elif val is None: 
    332333                    val = '--' 
    333334                elif name in self.time_fields: 
    334                     val = datetime.fromtimestamp(int(val or 0), utc) 
     335                    val = from_utimestamp(val) 
    335336                elif field and field['type'] == 'checkbox': 
    336337                    try: 
    337338                        val = bool(int(val)) 
     
    466467        def get_timestamp(date): 
    467468            if date: 
    468469                try: 
    469                     return to_timestamp(parse_date(date, req.tz)) 
     470                    return to_utimestamp(parse_date(date, req.tz)) 
    470471                except TracError, e: 
    471472                    errors.append(unicode(e)) 
    472473            return None 
  • trac/ticket/roadmap.py

    diff --git a/trac/ticket/roadmap.py b/trac/ticket/roadmap.py
    a b  
    1818from StringIO import StringIO 
    1919from datetime import datetime 
    2020import re 
    21 from time import time 
    2221 
    2322from genshi.builder import tag 
    2423 
     
    3029from trac.perm import IPermissionRequestor 
    3130from trac.resource import * 
    3231from trac.search import ISearchSource, search_to_sql, shorten_result 
    33 from trac.util.datefmt import parse_date, utc, to_timestamp, to_datetime, \ 
     32from trac.util.datefmt import parse_date, utc, to_utimestamp, \ 
    3433                              get_date_format_hint, get_datetime_format_hint, \ 
    35                               format_date, format_datetime 
     34                              format_date, format_datetime, from_utimestamp 
    3635from trac.util.text import CRLF 
    3736from trac.util.translation import _ 
    3837from trac.ticket import Milestone, Ticket, TicketSystem, group_milestones 
     
    472471                                   (ticket.id,)) 
    473472                    row = cursor.fetchone() 
    474473                    if row: 
    475                         write_utctime('COMPLETED', to_datetime(row[0], utc)) 
     474                        write_utctime('COMPLETED', from_utimestamp(row[0])) 
    476475                write_prop('END', 'VTODO') 
    477476        write_prop('END', 'VCALENDAR') 
    478477 
     
    527526            # TODO: creation and (later) modifications should also be reported 
    528527            cursor.execute("SELECT completed,name,description FROM milestone " 
    529528                           "WHERE completed>=%s AND completed<=%s", 
    530                            (to_timestamp(start), to_timestamp(stop))) 
     529                           (to_utimestamp(start), to_utimestamp(stop))) 
    531530            for completed, name, description in cursor: 
    532531                milestone = milestone_realm(id=name) 
    533532                if 'MILESTONE_VIEW' in req.perm(milestone): 
    534                     yield('milestone', datetime.fromtimestamp(completed, utc), 
     533                    yield('milestone', from_utimestamp(completed), 
    535534                          '', (milestone, description)) # FIXME: author? 
    536535 
    537536            # Attachments 
     
    862861        for name, due, completed, description in cursor: 
    863862            milestone = milestone_realm(id=name) 
    864863            if 'MILESTONE_VIEW' in req.perm(milestone): 
     864                dt = (completed and from_utimestamp(completed) or 
     865                      due and from_utimestamp(due) or datetime.now(utc)) 
    865866                yield (get_resource_url(self.env, milestone, req.href), 
    866                        get_resource_name(self.env, milestone), 
    867                        datetime.fromtimestamp( 
    868                            completed or due or time(), utc), 
     867                       get_resource_name(self.env, milestone), dt, 
    869868                       '', shorten_result(description, terms)) 
    870869         
    871870        # Attachments 
  • trac/ticket/templates/report.rss

    diff --git a/trac/ticket/templates/report.rss b/trac/ticket/templates/report.rss
    a b  
    2626                </py:when> 
    2727                <py:when test="col in ('time', 'changetime', 'created', 'modified')"> 
    2828                  <!-- FIXME: we end up with multiple pubDate --> 
    29                   <pubDate py:if="cell.value != 'None'">${http_date(fromtimestamp(int(cell.value)))}</pubDate> 
     29                  <pubDate py:if="cell.value != 'None'">${http_date(from_utimestamp(long(cell.value)))}</pubDate> 
    3030                </py:when> 
    3131                <py:when test="col == 'summary'"> 
    3232                  <title>#$row.id: $cell.value</title> 
  • trac/ticket/templates/report_view.html

    diff --git a/trac/ticket/templates/report_view.html b/trac/ticket/templates/report_view.html
    a b  
    144144 
    145145                        <!--! generic fields --> 
    146146                        <py:when test="col == 'time'"> 
    147                           <td class="date" py:attrs="td_attrs">${cell.value != '' and format_time(int(cell.value)) or '--'} 
     147                          <td class="date" py:attrs="td_attrs">${cell.value != '' and format_time(from_utimestamp(long(cell.value))) or '--'} 
    148148                            <hr py:if="fullrow"/> 
    149149                          </td> 
    150150                        </py:when> 
    151151 
    152152                        <py:when test="col in ('date', 'created', 'modified')"> 
    153                           <td class="date" py:attrs="td_attrs">${cell.value != '' and format_date(int(cell.value)) or '--'} 
     153                          <td class="date" py:attrs="td_attrs">${cell.value != '' and format_date(from_utimestamp(long(cell.value))) or '--'} 
    154154                            <hr py:if="fullrow"/> 
    155155                          </td> 
    156156                        </py:when> 
    157157 
    158158                        <py:when test="col == 'datetime'"> 
    159                           <td class="date" py:attrs="td_attrs">${cell.value != '' and format_datetime(int(cell.value)) or '--'} 
     159                          <td class="date" py:attrs="td_attrs">${cell.value != '' and format_datetime(from_utimestamp(long(cell.value))) or '--'} 
    160160                            <hr py:if="fullrow"/> 
    161161                          </td> 
    162162                        </py:when> 
  • trac/ticket/tests/model.py

    diff --git a/trac/ticket/tests/model.py b/trac/ticket/tests/model.py
    a b  
    44from trac.ticket.model import Ticket, Component, Milestone, Priority, Type, Version 
    55from trac.ticket.api import ITicketChangeListener 
    66from trac.test import EnvironmentStub 
    7 from trac.util.datefmt import utc, to_timestamp 
     7from trac.util.datefmt import utc, to_utimestamp 
    88 
    99from datetime import datetime 
    1010import unittest 
     
    300300                       "                        description,author,ipnr) " 
    301301                       "VALUES ('ticket',%s,'file.txt',1234,%s," 
    302302                       "        'My file','mark','')", 
    303                        (str(tkt_id), to_timestamp(t2))) 
     303                       (str(tkt_id), to_utimestamp(t2))) 
    304304        db.commit() 
    305305        t3 = datetime(2001, 1, 1, 1, 1, 3, 0, utc) 
    306306        ticket.save_changes('jim', 'Other', t3) 
     
    312312                          sorted(log[1:3])) 
    313313        self.assertEqual((t3, 'jim', 'comment', '', 'Other', True), log[3]) 
    314314 
     315    def test_subsecond_change(self): 
     316        """Perform two ticket changes within a second.""" 
     317        tkt_id = self._insert_ticket('Test', reporter='joe', component='foo') 
     318        ticket = Ticket(self.env, tkt_id) 
     319        t1 = datetime(2001, 1, 1, 1, 1, 1, 123456, utc) 
     320        ticket.save_changes('jane', 'Testing', t1) 
     321        t2 = datetime(2001, 1, 1, 1, 1, 1, 789012, utc) 
     322        ticket.save_changes('jim', 'Other', t2) 
     323        log = ticket.get_changelog() 
     324        self.assertEqual(2, len(log)) 
     325        self.assertEqual((t1, 'jane', 'comment', '', 'Testing', True), log[0]) 
     326        self.assertEqual((t2, 'jim', 'comment', '', 'Other', True), log[1]) 
     327 
    315328    def test_changelog_with_reverted_change(self): 
    316329        tkt_id = self._insert_ticket('Test', reporter='joe', component='foo') 
    317330        ticket = Ticket(self.env, tkt_id) 
     
    520533 
    521534        cursor = self.db.cursor() 
    522535        cursor.execute("SELECT * FROM milestone WHERE name='Test'") 
    523         self.assertEqual(('Test', to_timestamp(t1), to_timestamp(t2), 'Foo bar'), 
     536        self.assertEqual(('Test', to_utimestamp(t1), to_utimestamp(t2), 
     537                          'Foo bar'), 
    524538                         cursor.fetchone()) 
    525539 
    526540    def test_update_milestone_without_name(self): 
  • trac/ticket/tests/query.py

    diff --git a/trac/ticket/tests/query.py b/trac/ticket/tests/query.py
    a b  
    359359WHERE (((%(cast_time)s>=%%s AND %(cast_time)s<%%s))) 
    360360ORDER BY COALESCE(t.id,0)=0,t.id""" % { 
    361361          'cast_time': self.env.get_db_cnx().cast('t.time', 'int')}) 
    362         self.assertEqual([1217548800, 1220227200], args) 
     362        self.assertEqual([1217548800000000L, 1220227200000000L], args) 
    363363        tickets = query.execute(self.req) 
    364364 
    365365    def test_constrained_by_time_range_exclusion(self): 
     
    372372WHERE ((NOT (%(cast_time)s>=%%s AND %(cast_time)s<%%s))) 
    373373ORDER BY COALESCE(t.id,0)=0,t.id""" % { 
    374374          'cast_time': self.env.get_db_cnx().cast('t.time', 'int')}) 
    375         self.assertEqual([1217548800, 1220227200], args) 
     375        self.assertEqual([1217548800000000L, 1220227200000000L], args) 
    376376        tickets = query.execute(self.req) 
    377377 
    378378    def test_constrained_by_time_range_open_right(self): 
     
    385385WHERE ((%(cast_time)s>=%%s)) 
    386386ORDER BY COALESCE(t.id,0)=0,t.id""" % { 
    387387          'cast_time': self.env.get_db_cnx().cast('t.time', 'int')}) 
    388         self.assertEqual([1217548800], args) 
     388        self.assertEqual([1217548800000000L], args) 
    389389        tickets = query.execute(self.req) 
    390390 
    391391    def test_constrained_by_time_range_open_left(self): 
     
    398398WHERE ((%(cast_time)s<%%s)) 
    399399ORDER BY COALESCE(t.id,0)=0,t.id""" % { 
    400400          'cast_time': self.env.get_db_cnx().cast('t.time', 'int')}) 
    401         self.assertEqual([1220227200], args) 
     401        self.assertEqual([1220227200000000L], args) 
    402402        tickets = query.execute(self.req) 
    403403 
    404404    def test_constrained_by_time_range_modified(self): 
     
    411411WHERE (((%(cast_changetime)s>=%%s AND %(cast_changetime)s<%%s))) 
    412412ORDER BY COALESCE(t.id,0)=0,t.id""" % { 
    413413          'cast_changetime': self.env.get_db_cnx().cast('t.changetime', 'int')}) 
    414         self.assertEqual([1217548800, 1220227200], args) 
     414        self.assertEqual([1217548800000000L, 1220227200000000L], args) 
    415415        tickets = query.execute(self.req) 
    416416 
    417417    def test_constrained_by_keywords(self): 
  • trac/ticket/web_ui.py

    diff --git a/trac/ticket/web_ui.py b/trac/ticket/web_ui.py
    a b  
    3636from trac.timeline.api import ITimelineEventProvider 
    3737from trac.util import get_reporter_id 
    3838from trac.util.compat import any 
    39 from trac.util.datefmt import format_datetime, to_timestamp, utc 
     39from trac.util.datefmt import format_datetime, from_utimestamp, \ 
     40                              to_utimestamp, utc 
    4041from trac.util.text import exception_to_unicode, obfuscate_email_address,  \ 
    4142                           shorten_line, to_unicode 
    4243from trac.util.presentation import separated 
     
    209210                           ': ', 
    210211                           ticketsystem.format_summary(summary, status, 
    211212                                                       resolution, type)), 
    212                        datetime.fromtimestamp(ts, utc), author, 
     213                       from_utimestamp(ts), author, 
    213214                       shorten_result(desc, terms)) 
    214215         
    215216        # Attachments 
     
    226227                yield ('ticket_details', _('Ticket updates'), False) 
    227228 
    228229    def get_timeline_events(self, req, start, stop, filters): 
    229         ts_start = to_timestamp(start) 
    230         ts_stop = to_timestamp(stop) 
     230        ts_start = to_utimestamp(start) 
     231        ts_stop = to_utimestamp(stop) 
    231232 
    232233        status_map = {'new': ('newticket', N_('created')), 
    233234                      'reopened': ('reopenedticket', N_('reopened')), 
     
    263264            else: 
    264265                return None 
    265266            kind, verb = status_map[status] 
    266             return (kind, datetime.fromtimestamp(ts, utc), author, 
     267            return (kind, from_utimestamp(ts), author, 
    267268                    (ticket, verb, info, summary, status, resolution, type, 
    268269                     description, comment, cid)) 
    269270 
     
    16281629                rev = int(field[8:]) 
    16291630                comment_history.setdefault(rev, {}).update({'comment': old}) 
    16301631                comment_history.setdefault(rev + 1, {}).update( 
    1631                         {'author': author, 
    1632                          'date': datetime.fromtimestamp(int(new), utc)}) 
     1632                        {'author': author, 'date': from_utimestamp(long(new))}) 
    16331633            elif old or new: 
    16341634                current['fields'][field] = {'old': old, 'new': new} 
    16351635        if current: 
  • trac/upgrades/db15.py

    diff --git a/trac/upgrades/db15.py b/trac/upgrades/db15.py
    a b  
    1010        Column('authenticated', type='int'), 
    1111        Column('var_name'), 
    1212        Column('var_value')] 
    13     db_backend, _ = DatabaseManager(env)._get_connector() 
     13    db_backend, _ = DatabaseManager(env).get_connector() 
    1414    for stmt in db_backend.to_sql(session_table): 
    1515        cursor.execute(stmt) 
    1616 
  • trac/upgrades/db17.py

    diff --git a/trac/upgrades/db17.py b/trac/upgrades/db17.py
    a b  
    1616        Column('base_rev'), 
    1717        Index(['rev']) 
    1818    ] 
    19     db_connector, _ = DatabaseManager(env)._get_connector() 
     19    db_connector, _ = DatabaseManager(env).get_connector() 
    2020    for stmt in db_connector.to_sql(table): 
    2121        cursor.execute(stmt) 
    2222 
  • trac/upgrades/db18.py

    diff --git a/trac/upgrades/db18.py b/trac/upgrades/db18.py
    a b  
    2929                Index(['ticket']), 
    3030                Index(['time'])]] 
    3131     
    32     db_connector, _ = DatabaseManager(env)._get_connector() 
     32    db_connector, _ = DatabaseManager(env).get_connector() 
    3333    for table in tables: 
    3434        for stmt in db_connector.to_sql(table): 
    3535            cursor.execute(stmt) 
  • trac/upgrades/db19.py

    diff --git a/trac/upgrades/db19.py b/trac/upgrades/db19.py
    a b  
    1313        Column('query'), 
    1414        Column('description') 
    1515    ] 
    16     db_connector, _ = DatabaseManager(env)._get_connector() 
     16    db_connector, _ = DatabaseManager(env).get_connector() 
    1717    for stmt in db_connector.to_sql(table): 
    1818        cursor.execute(stmt) 
    1919 
  • trac/upgrades/db22.py

    diff --git a/trac/upgrades/db22.py b/trac/upgrades/db22.py
    a b  
    66        Column('id'), 
    77        Column('generation', type='int') 
    88    ] 
    9     db_connector, _ = DatabaseManager(env)._get_connector() 
     9    db_connector, _ = DatabaseManager(env).get_connector() 
    1010    for stmt in db_connector.to_sql(table): 
    1111        cursor.execute(stmt) 
  • new file trac/upgrades/db23.py

    diff --git a/trac/upgrades/db23.py b/trac/upgrades/db23.py
    new file mode 100644
    - +  
     1from trac.db import DatabaseManager 
     2 
     3 
     4def do_upgrade(env, ver, cursor): 
     5    """Convert time values from integer seconds to integer microseconds.""" 
     6    tables = [ 
     7        ('attachment', {'time': ('int', 'int64')}), 
     8        ('wiki', {'time': ('int', 'int64')}), 
     9        ('revision', {'time': ('int', 'int64')}), 
     10        ('ticket', {'time': ('int', 'int64'), 
     11                    'changetime': ('int', 'int64')}), 
     12        ('ticket_change', {'time': ('int', 'int64')}), 
     13        ('milestone', {'due': ('int', 'int64'), 
     14                       'completed': ('int', 'int64')}), 
     15        ('version', {'time': ('int', 'int64')}), 
     16    ] 
     17     
     18    db_connector, _ = DatabaseManager(env).get_connector() 
     19    db = env.get_db_cnx() 
     20    for table, columns in tables: 
     21        # Alter column types 
     22        for sql in db_connector.alter_column_types(table, columns): 
     23            cursor.execute(sql) 
     24         
     25        # Convert timestamps to microseconds 
     26        cursor.execute("UPDATE %s SET %s" % (table, 
     27                        ', '.join("%s=%s*1000000" % (column, column) 
     28                                  for column in columns))) 
     29     
     30    # Convert comment edit timestamps to microseconds 
     31    cursor.execute("UPDATE ticket_change SET newvalue=%s*1000000 " 
     32                   "WHERE field %s" % (db.cast('newvalue', 'int'), db.like()), 
     33                   ('_comment%',)) 
  • trac/util/datefmt.py

    diff --git a/trac/util/datefmt.py b/trac/util/datefmt.py
    a b  
    6161    else: 
    6262        return 0 
    6363 
     64def to_utimestamp(dt): 
     65    """Return a microsecond POSIX timestamp for the given `datetime`.""" 
     66    if not dt: 
     67        return 0 
     68    diff = dt - _epoc 
     69    return (diff.days * 86400000000L + diff.seconds * 1000000 
     70            + diff.microseconds) 
     71 
     72def from_utimestamp(ts): 
     73    """Return the `datetime` for the given microsecond POSIX timestamp.""" 
     74    return _epoc + timedelta(microseconds=ts or 0) 
    6475 
    6576# -- formatting 
    6677 
  • trac/util/tests/datefmt.py

    diff --git a/trac/util/tests/datefmt.py b/trac/util/tests/datefmt.py
    a b  
    4242                             tz.utcoffset(None)) 
    4343            self.assertEqual('GMT +4:00', tz.zone) 
    4444 
     45 
    4546class DateFormatTestCase(unittest.TestCase): 
    4647 
    4748    def test_to_datetime(self): 
     
    9495        self.assertEqual('2009-08-20',  
    9596                         datefmt.format_date(a_date, format='%Y-%m-%d')) 
    9697 
     98 
     99class UTimestampTestCase(unittest.TestCase): 
     100     
     101    def test_sub_second(self): 
     102        t = datetime.datetime(2001, 2, 3, 4, 5, 6, 123456, datefmt.utc) 
     103        ts = datefmt.to_utimestamp(t) 
     104        self.assertEqual(t, datefmt.from_utimestamp(ts)) 
     105 
     106 
    97107def suite(): 
    98108    suite = unittest.TestSuite() 
    99109    if PytzTestCase: 
     
    101111    else: 
    102112        print "SKIP: utils/tests/datefmt.py (no pytz installed)" 
    103113    suite.addTest(unittest.makeSuite(DateFormatTestCase)) 
     114    suite.addTest(unittest.makeSuite(UTimestampTestCase)) 
    104115    return suite 
    105116 
    106117if __name__ == '__main__': 
  • trac/versioncontrol/cache.py

    diff --git a/trac/versioncontrol/cache.py b/trac/versioncontrol/cache.py
    a b  
    1414# 
    1515# Author: Christopher Lenz <cmlenz@gmx.de> 
    1616 
    17 from datetime import datetime 
    1817import os 
    1918import posixpath 
    2019 
    2120from trac.core import TracError 
    22 from trac.util.datefmt import utc, to_timestamp 
     21from trac.util.datefmt import from_utimestamp, to_utimestamp 
    2322from trac.util.translation import _ 
    2423from trac.versioncontrol import Changeset, Node, Repository, Authorizer, \ 
    2524                                NoSuchChangeset 
     
    6766        cursor.execute("SELECT rev FROM revision " 
    6867                       "WHERE time >= %s AND time < %s " 
    6968                       "ORDER BY time DESC, rev DESC", 
    70                        (to_timestamp(start), to_timestamp(stop))) 
     69                       (to_utimestamp(start), to_utimestamp(stop))) 
    7170        for rev, in cursor: 
    7271            try: 
    7372                if self.authz.has_permission_for_changeset(rev): 
     
    8079        db = self.getdb() 
    8180        cursor = db.cursor() 
    8281        cursor.execute("UPDATE revision SET time=%s, author=%s, message=%s " 
    83                        "WHERE rev=%s", (to_timestamp(cset.date), 
     82                       "WHERE rev=%s", (to_utimestamp(cset.date), 
    8483                                        cset.author, cset.message, 
    8584                                        (str(cset.rev)))) 
    8685        db.commit() 
     
    187186                                       " (rev,time,author,message) " 
    188187                                       "VALUES (%s,%s,%s,%s)", 
    189188                                       (str(next_youngest), 
    190                                         to_timestamp(cset.date), 
     189                                        to_utimestamp(cset.date), 
    191190                                        cset.author, cset.message)) 
    192191                    except Exception, e: # *another* 1.1. resync attempt won  
    193192                        self.log.warning('Revision %s already cached: %s' % 
     
    346345        cursor = db.cursor() 
    347346        cursor.execute("SELECT time,author,message FROM revision " 
    348347                       "WHERE rev=%s", (str(rev),)) 
    349         row = cursor.fetchone() 
    350         if row: 
    351             _date, author, message = row 
    352             date = datetime.fromtimestamp(_date, utc) 
     348        for _date, author, message in cursor: 
     349            date = from_utimestamp(_date) 
    353350            Changeset.__init__(self, rev, message, author, date) 
     351            break 
    354352        else: 
    355353            raise NoSuchChangeset(rev) 
    356354        self.scope = getattr(repos, 'scope', '') 
  • trac/versioncontrol/svn_fs.py

    diff --git a/trac/versioncontrol/svn_fs.py b/trac/versioncontrol/svn_fs.py
    a b  
    4747import os.path 
    4848import weakref 
    4949import posixpath 
    50 from datetime import datetime 
    5150 
    5251from trac.config import ListOption 
    5352from trac.core import * 
     
    5958from trac.util import embedded_numbers 
    6059from trac.util.text import exception_to_unicode, to_unicode 
    6160from trac.util.translation import _ 
    62 from trac.util.datefmt import utc 
     61from trac.util.datefmt import from_utimestamp 
    6362 
    6463 
    6564application_pool = None 
     
    781780                                 core.SVN_PROP_REVISION_DATE, self.pool()) 
    782781        if not _date: 
    783782            return None 
    784         ts = core.svn_time_from_cstring(_date, self.pool()) / 1000000 
    785         return datetime.fromtimestamp(ts, utc) 
     783        return from_utimestamp(core.svn_time_from_cstring(_date, self.pool())) 
    786784 
    787785    def _get_prop(self, name): 
    788786        return fs.node_prop(self.root, self._scoped_path_utf8, name, 
     
    847845        author = author and to_unicode(author, 'utf-8') 
    848846        _date = self._get_prop(core.SVN_PROP_REVISION_DATE) 
    849847        if _date: 
    850             ts = core.svn_time_from_cstring(_date, self.pool()) / 1000000 
    851             date = datetime.fromtimestamp(ts, utc) 
     848            ts = core.svn_time_from_cstring(_date, self.pool()) 
     849            date = from_utimestamp(ts) 
    852850        else: 
    853851            date = None 
    854852        Changeset.__init__(self, rev, message, author, date) 
  • trac/versioncontrol/tests/cache.py

    diff --git a/trac/versioncontrol/tests/cache.py b/trac/versioncontrol/tests/cache.py
    a b  
    1818 
    1919from trac.log import logger_factory 
    2020from trac.test import Mock, InMemoryDatabase 
    21 from trac.util.datefmt import to_timestamp, utc 
     21from trac.util.datefmt import to_utimestamp, utc 
    2222from trac.versioncontrol import Repository, Changeset, Node, NoSuchChangeset 
    2323from trac.versioncontrol.cache import CachedRepository 
    2424 
     
    7373 
    7474        cursor = self.db.cursor() 
    7575        cursor.execute("SELECT rev,time,author,message FROM revision") 
    76         self.assertEquals(('0', to_timestamp(t1), '', ''), cursor.fetchone()) 
    77         self.assertEquals(('1', to_timestamp(t2), 'joe', 'Import'), cursor.fetchone()) 
     76        self.assertEquals(('0', to_utimestamp(t1), '', ''), cursor.fetchone()) 
     77        self.assertEquals(('1', to_utimestamp(t2), 'joe', 'Import'), cursor.fetchone()) 
    7878        self.assertEquals(None, cursor.fetchone()) 
    7979        cursor.execute("SELECT rev,path,node_type,change_type,base_path," 
    8080                       "base_rev FROM node_change") 
     
    9090        t3 = datetime(2003, 1, 1, 1, 1, 1, 0, utc) 
    9191        cursor = self.db.cursor() 
    9292        cursor.execute("INSERT INTO revision (rev,time,author,message) " 
    93                        "VALUES (0,%s,'','')", (to_timestamp(t1),)) 
     93                       "VALUES (0,%s,'','')", (to_utimestamp(t1),)) 
    9494        cursor.execute("INSERT INTO revision (rev,time,author,message) " 
    95                        "VALUES (1,%s,'joe','Import')", (to_timestamp(t2),)) 
     95                       "VALUES (1,%s,'joe','Import')", (to_utimestamp(t2),)) 
    9696        cursor.executemany("INSERT INTO node_change (rev,path,node_type," 
    9797                           "change_type,base_path,base_rev) " 
    9898                           "VALUES ('1',%s,%s,%s,%s,%s)", 
     
    114114 
    115115        cursor = self.db.cursor() 
    116116        cursor.execute("SELECT time,author,message FROM revision WHERE rev='2'") 
    117         self.assertEquals((to_timestamp(t3), 'joe', 'Update'), cursor.fetchone()) 
     117        self.assertEquals((to_utimestamp(t3), 'joe', 'Update'), cursor.fetchone()) 
    118118        self.assertEquals(None, cursor.fetchone()) 
    119119        cursor.execute("SELECT path,node_type,change_type,base_path,base_rev " 
    120120                       "FROM node_change WHERE rev='2'") 
     
    127127        t2 = datetime(2002, 1, 1, 1, 1, 1, 0, utc) 
    128128        cursor = self.db.cursor() 
    129129        cursor.execute("INSERT INTO revision (rev,time,author,message) " 
    130                        "VALUES (0,%s,'','')", (to_timestamp(t1),)) 
     130                       "VALUES (0,%s,'','')", (to_utimestamp(t1),)) 
    131131        cursor.execute("INSERT INTO revision (rev,time,author,message) " 
    132                        "VALUES (1,%s,'joe','Import')", (to_timestamp(t2),)) 
     132                       "VALUES (1,%s,'joe','Import')", (to_utimestamp(t2),)) 
    133133        cursor.executemany("INSERT INTO node_change (rev,path,node_type," 
    134134                           "change_type,base_path,base_rev) " 
    135135                           "VALUES ('1',%s,%s,%s,%s,%s)", 
  • trac/versioncontrol/tests/svn_fs.py

    diff --git a/trac/versioncontrol/tests/svn_fs.py b/trac/versioncontrol/tests/svn_fs.py
    a b  
    145145        self.assertEqual(u'/tête', node.path) 
    146146        self.assertEqual(Node.DIRECTORY, node.kind) 
    147147        self.assertEqual(HEAD, node.rev) 
    148         self.assertEqual(datetime(2007, 4, 30, 17, 45, 26, 0, utc), 
     148        self.assertEqual(datetime(2007, 4, 30, 17, 45, 26, 234375, utc), 
    149149                         node.last_modified) 
    150150        node = self.repos.get_node(u'/tête/README.txt') 
    151151        self.assertEqual('README.txt', node.name) 
    152152        self.assertEqual(u'/tête/README.txt', node.path) 
    153153        self.assertEqual(Node.FILE, node.kind) 
    154154        self.assertEqual(3, node.rev) 
    155         self.assertEqual(datetime(2005, 4, 1, 13, 24, 58, 0, utc), node.last_modified) 
     155        self.assertEqual(datetime(2005, 4, 1, 13, 24, 58, 234643, utc), node.last_modified) 
    156156 
    157157    def test_get_node_specific_rev(self): 
    158158        node = self.repos.get_node(u'/tête', 1) 
     
    160160        self.assertEqual(u'/tête', node.path) 
    161161        self.assertEqual(Node.DIRECTORY, node.kind) 
    162162        self.assertEqual(1, node.rev) 
    163         self.assertEqual(datetime(2005, 4, 1, 10, 0, 52, 0, utc), node.last_modified) 
     163        self.assertEqual(datetime(2005, 4, 1, 10, 0, 52, 353248, utc), node.last_modified) 
    164164        node = self.repos.get_node(u'/tête/README.txt', 2) 
    165165        self.assertEqual('README.txt', node.name) 
    166166        self.assertEqual(u'/tête/README.txt', node.path) 
    167167        self.assertEqual(Node.FILE, node.kind) 
    168168        self.assertEqual(2, node.rev) 
    169         self.assertEqual(datetime(2005, 4, 1, 13, 12, 18, 0, utc), node.last_modified) 
     169        self.assertEqual(datetime(2005, 4, 1, 13, 12, 18, 216267, utc), node.last_modified) 
    170170 
    171171    def test_get_dir_entries(self): 
    172172        node = self.repos.get_node(u'/tête') 
     
    383383        self.assertEqual(0, chgset.rev) 
    384384        self.assertEqual('', chgset.message) 
    385385        self.assertEqual('', chgset.author) 
    386         self.assertEqual(datetime(2005, 4, 1, 9, 57, 41, 0, utc), chgset.date) 
     386        self.assertEqual(datetime(2005, 4, 1, 9, 57, 41, 312767, utc), chgset.date) 
    387387        self.assertRaises(StopIteration, chgset.get_changes().next) 
    388388 
    389389    def test_changeset_added_dirs(self): 
     
    391391        self.assertEqual(1, chgset.rev) 
    392392        self.assertEqual('Initial directory layout.', chgset.message) 
    393393        self.assertEqual('john', chgset.author) 
    394         self.assertEqual(datetime(2005, 4, 1, 10, 0, 52, 0, utc), chgset.date) 
     394        self.assertEqual(datetime(2005, 4, 1, 10, 0, 52, 353248, utc), chgset.date) 
    395395 
    396396        changes = chgset.get_changes() 
    397397        self.assertEqual(('branches', Node.DIRECTORY, Changeset.ADD, None, -1), 
     
    407407        self.assertEqual(3, chgset.rev) 
    408408        self.assertEqual('Fixed README.\n', chgset.message) 
    409409        self.assertEqual('kate', chgset.author) 
    410         self.assertEqual(datetime(2005, 4, 1, 13, 24, 58, 0, utc), chgset.date) 
     410        self.assertEqual(datetime(2005, 4, 1, 13, 24, 58, 234643, utc), chgset.date) 
    411411 
    412412        changes = chgset.get_changes() 
    413413        self.assertEqual((u'tête/README.txt', Node.FILE, Changeset.EDIT, 
     
    419419        self.assertEqual(5, chgset.rev) 
    420420        self.assertEqual('Moved directories.', chgset.message) 
    421421        self.assertEqual('kate', chgset.author) 
    422         self.assertEqual(datetime(2005, 4, 1, 16, 25, 39, 0, utc), chgset.date) 
     422        self.assertEqual(datetime(2005, 4, 1, 16, 25, 39, 658099, utc), chgset.date) 
    423423 
    424424        changes = chgset.get_changes() 
    425425        self.assertEqual((u'tête/dir1/dir2', Node.DIRECTORY, Changeset.MOVE, 
     
    433433        self.assertEqual(6, chgset.rev) 
    434434        self.assertEqual('More things to read', chgset.message) 
    435435        self.assertEqual('john', chgset.author) 
    436         self.assertEqual(datetime(2005, 4, 1, 18, 56, 46, 0, utc), chgset.date) 
     436        self.assertEqual(datetime(2005, 4, 1, 18, 56, 46, 985846, utc), chgset.date) 
    437437 
    438438        changes = chgset.get_changes() 
    439439        self.assertEqual((u'tête/README2.txt', Node.FILE, Changeset.COPY, 
     
    550550        self.assertEqual('/dir1', node.path) 
    551551        self.assertEqual(Node.DIRECTORY, node.kind) 
    552552        self.assertEqual(5, node.rev) 
    553         self.assertEqual(datetime(2005, 4, 1, 16, 25, 39, 0, utc), node.last_modified) 
     553        self.assertEqual(datetime(2005, 4, 1, 16, 25, 39, 658099, utc), node.last_modified) 
    554554        node = self.repos.get_node('/README.txt') 
    555555        self.assertEqual('README.txt', node.name) 
    556556        self.assertEqual('/README.txt', node.path) 
    557557        self.assertEqual(Node.FILE, node.kind) 
    558558        self.assertEqual(3, node.rev) 
    559         self.assertEqual(datetime(2005, 4, 1, 13, 24, 58, 0, utc), node.last_modified) 
     559        self.assertEqual(datetime(2005, 4, 1, 13, 24, 58, 234643, utc), node.last_modified) 
    560560 
    561561    def test_get_node_specific_rev(self): 
    562562        node = self.repos.get_node('/dir1', 4) 
     
    564564        self.assertEqual('/dir1', node.path) 
    565565        self.assertEqual(Node.DIRECTORY, node.kind) 
    566566        self.assertEqual(4, node.rev) 
    567         self.assertEqual(datetime(2005, 4, 1, 15, 42, 35, 0, utc), node.last_modified) 
     567        self.assertEqual(datetime(2005, 4, 1, 15, 42, 35, 450595, utc), node.last_modified) 
    568568        node = self.repos.get_node('/README.txt', 2) 
    569569        self.assertEqual('README.txt', node.name) 
    570570        self.assertEqual('/README.txt', node.path) 
    571571        self.assertEqual(Node.FILE, node.kind) 
    572572        self.assertEqual(2, node.rev) 
    573         self.assertEqual(datetime(2005, 4, 1, 13, 12, 18, 0, utc), node.last_modified) 
     573        self.assertEqual(datetime(2005, 4, 1, 13, 12, 18, 216267, utc), node.last_modified) 
    574574 
    575575    def test_get_dir_entries(self): 
    576576        node = self.repos.get_node('/') 
     
    675675        self.assertEqual(0, chgset.rev) 
    676676        self.assertEqual('', chgset.message) 
    677677        self.assertEqual('', chgset.author) 
    678         self.assertEqual(datetime(2005, 4, 1, 9, 57, 41, 0, utc), chgset.date) 
     678        self.assertEqual(datetime(2005, 4, 1, 9, 57, 41, 312767, utc), chgset.date) 
    679679        self.assertRaises(StopIteration, chgset.get_changes().next) 
    680680 
    681681    def test_changeset_added_dirs(self): 
     
    683683        self.assertEqual(4, chgset.rev) 
    684684        self.assertEqual('More directories.', chgset.message) 
    685685        self.assertEqual('john', chgset.author) 
    686         self.assertEqual(datetime(2005, 4, 1, 15, 42, 35, 0, utc), chgset.date) 
     686        self.assertEqual(datetime(2005, 4, 1, 15, 42, 35, 450595, utc), chgset.date) 
    687687 
    688688        changes = chgset.get_changes() 
    689689        self.assertEqual(('dir1', Node.DIRECTORY, 'add', None, -1), 
     
    699699        self.assertEqual(3, chgset.rev) 
    700700        self.assertEqual('Fixed README.\n', chgset.message) 
    701701        self.assertEqual('kate', chgset.author) 
    702         self.assertEqual(datetime(2005, 4, 1, 13, 24, 58, 0, utc), chgset.date) 
     702        self.assertEqual(datetime(2005, 4, 1, 13, 24, 58, 234643, utc), chgset.date) 
    703703 
    704704        changes = chgset.get_changes() 
    705705        self.assertEqual(('README.txt', Node.FILE, Changeset.EDIT, 
     
    711711        self.assertEqual(5, chgset.rev) 
    712712        self.assertEqual('Moved directories.', chgset.message) 
    713713        self.assertEqual('kate', chgset.author) 
    714         self.assertEqual(datetime(2005, 4, 1, 16, 25, 39, 0, utc), chgset.date) 
     714        self.assertEqual(datetime(2005, 4, 1, 16, 25, 39, 658099, utc), chgset.date) 
    715715 
    716716        changes = chgset.get_changes() 
    717717        self.assertEqual(('dir1/dir2', Node.DIRECTORY, Changeset.MOVE, 
     
    725725        self.assertEqual(6, chgset.rev) 
    726726        self.assertEqual('More things to read', chgset.message) 
    727727        self.assertEqual('john', chgset.author) 
    728         self.assertEqual(datetime(2005, 4, 1, 18, 56, 46, 0, utc), chgset.date) 
     728        self.assertEqual(datetime(2005, 4, 1, 18, 56, 46, 985846, utc), chgset.date) 
    729729 
    730730        changes = chgset.get_changes() 
    731731        self.assertEqual(('README2.txt', Node.FILE, Changeset.COPY, 
  • trac/versioncontrol/web_ui/changeset.py

    diff --git a/trac/versioncontrol/web_ui/changeset.py b/trac/versioncontrol/web_ui/changeset.py
    a b  
    1818#         Christopher Lenz <cmlenz@gmx.de> 
    1919#         Christian Boos <cboos@neuf.fr> 
    2020 
    21 from datetime import datetime 
    2221from itertools import groupby 
    2322import os 
    2423import posixpath 
     
    3635from trac.timeline.api import ITimelineEventProvider 
    3736from trac.util import embedded_numbers, content_disposition 
    3837from trac.util.compat import any 
    39 from trac.util.datefmt import pretty_timedelta, utc 
     38from trac.util.datefmt import from_utimestamp, pretty_timedelta 
    4039from trac.util.text import exception_to_unicode, unicode_urlencode, \ 
    4140                           shorten_line, CRLF 
    4241from trac.util.translation import _ 
     
    991990                continue 
    992991            yield (req.href.changeset(rev), 
    993992                   '[%s]: %s' % (rev, shorten_line(log)), 
    994                    datetime.fromtimestamp(ts, utc), author, 
    995                    shorten_result(log, terms)) 
     993                   from_utimestamp(ts), author, shorten_result(log, terms)) 
    996994 
    997995 
    998996class AnyDiffModule(Component): 
  • trac/web/chrome.py

    diff --git a/trac/web/chrome.py b/trac/web/chrome.py
    a b  
    6565                           shorten_line, unicode_quote_plus, to_unicode, \ 
    6666                           javascript_quote, exception_to_unicode 
    6767from trac.util.datefmt import pretty_timedelta, format_datetime, format_date, \ 
    68                               format_time, http_date, utc 
     68                              format_time, from_utimestamp, http_date, utc 
    6969from trac.util.translation import _ 
    7070from trac.web.api import IRequestHandler, ITemplateStreamFilter, HTTPNotFound 
    7171from trac.web.href import Href 
     
    707707            'format_time': partial(format_time, tzinfo=tzinfo), 
    708708            'fromtimestamp': partial(datetime.datetime.fromtimestamp, 
    709709                                     tz=tzinfo), 
     710            'from_utimestamp': from_utimestamp, 
    710711 
    711712            # Wiki-formatting functions 
    712713            'wiki_to': partial(format_to, self.env), 
  • trac/web/tests/session.py

    diff --git a/trac/web/tests/session.py b/trac/web/tests/session.py
    a b  
    166166                       (0,)) 
    167167        cursor.execute("INSERT INTO session " 
    168168                       "VALUES ('987654', 0, %s)", 
    169                        (time.time() - PURGE_AGE - 3600,)) 
     169                       (int(time.time() - PURGE_AGE - 3600),)) 
    170170        cursor.execute("INSERT INTO session_attribute VALUES " 
    171171                       "('987654', 0, 'foo', 'bar')") 
    172172         
  • trac/wiki/admin.py

    diff --git a/trac/wiki/admin.py b/trac/wiki/admin.py
    a b  
    1515import os.path 
    1616import pkg_resources 
    1717import sys 
    18 import time 
    1918 
    2019from trac.admin import * 
    2120from trac.core import * 
    2221from trac.wiki import model 
    2322from trac.wiki.api import WikiSystem 
    2423from trac.util.compat import any 
    25 from trac.util.datefmt import format_datetime, utc 
     24from trac.util.datefmt import format_datetime, from_utimestamp, \ 
     25                              to_utimestamp, utc 
    2626from trac.util.text import to_unicode, unicode_quote, unicode_unquote, \ 
    2727                           print_table, printout 
    2828from trac.util.translation import _ 
     
    116116                       " SELECT 1+COALESCE(max(version),0),%s,%s," 
    117117                       " 'trac','127.0.0.1',%s FROM wiki " 
    118118                       " WHERE name=%s", 
    119                        (title, int(time.time()), data, title)) 
     119                       (title, to_utimestamp(datetime.now(utc)), data, title)) 
    120120        if not old: 
    121121            WikiSystem(self.env).pages.invalidate(db) 
    122122        if handle_ta: 
     
    161161        cursor.execute("SELECT name, max(version), max(time) " 
    162162                       "FROM wiki GROUP BY name ORDER BY name") 
    163163        print_table([(r[0], int(r[1]), 
    164                       format_datetime(datetime.fromtimestamp(r[2], utc), 
     164                      format_datetime(from_utimestamp(r[2]), 
    165165                                      console_datetime_format)) 
    166166                     for r in cursor], 
    167167                    [_('Title'), _('Edits'), _('Modified')]) 
  • trac/wiki/macros.py

    diff --git a/trac/wiki/macros.py b/trac/wiki/macros.py
    a b  
    1414# 
    1515# Author: Christopher Lenz <cmlenz@gmx.de> 
    1616 
    17 from datetime import datetime 
    1817from itertools import groupby 
    1918import inspect 
    2019import os 
     
    2625 
    2726from trac.core import * 
    2827from trac.resource import Resource, get_resource_url, get_resource_summary 
    29 from trac.util.datefmt import format_date, utc 
     28from trac.util.datefmt import format_date, from_utimestamp 
    3029from trac.util.html import escape 
    3130from trac.util.text import unquote, to_unicode 
    3231from trac.util.translation import _ 
     
    203202        for name, version, ts in cursor: 
    204203            if not 'WIKI_VIEW' in formatter.perm('wiki', name, version): 
    205204                continue 
    206             time = datetime.fromtimestamp(ts, utc) 
    207             date = format_date(time) 
     205            date = format_date(from_utimestamp(ts)) 
    208206            if date != prevdate: 
    209207                prevdate = date 
    210208                entries_per_date.append((date, [])) 
  • trac/wiki/model.py

    diff --git a/trac/wiki/model.py b/trac/wiki/model.py
    a b  
    2020 
    2121from trac.core import * 
    2222from trac.resource import Resource 
    23 from trac.util.datefmt import utc, to_timestamp 
     23from trac.util.datefmt import from_utimestamp, to_utimestamp, utc 
    2424from trac.util.translation import _ 
    2525from trac.wiki.api import WikiSystem 
    2626 
     
    6868            version, time, author, text, comment, readonly = row 
    6969            self.version = int(version) 
    7070            self.author = author 
    71             self.time = datetime.fromtimestamp(time, utc) 
     71            self.time = from_utimestamp(time) 
    7272            self.text = text 
    7373            self.comment = comment 
    7474            self.readonly = readonly and int(readonly) or 0 
     
    138138            cursor.execute("INSERT INTO wiki (name,version,time,author,ipnr," 
    139139                           "text,comment,readonly) VALUES (%s,%s,%s,%s,%s,%s," 
    140140                           "%s,%s)", (self.name, self.version + 1, 
    141                                       to_timestamp(t), author, remote_addr, 
     141                                      to_utimestamp(t), author, remote_addr, 
    142142                                      self.text, comment, self.readonly)) 
    143143            self.version += 1 
    144144            self.resource = self.resource(version=self.version) 
     
    174174                       "WHERE name=%s AND version<=%s " 
    175175                       "ORDER BY version DESC", (self.name, self.version)) 
    176176        for version, ts, author, comment, ipnr in cursor: 
    177             time = datetime.fromtimestamp(ts, utc) 
    178             yield version, time, author, comment, ipnr 
     177            yield version, from_utimestamp(ts), author, comment, ipnr 
  • trac/wiki/tests/model.py

    diff --git a/trac/wiki/tests/model.py b/trac/wiki/tests/model.py
    a b  
    33 
    44from trac.core import * 
    55from trac.test import EnvironmentStub 
    6 from trac.util.datefmt import utc, to_timestamp 
     6from trac.util.datefmt import utc, to_utimestamp 
    77from trac.wiki import WikiPage, IWikiChangeListener 
    88 
    99 
     
    4949        t = datetime(2001, 1, 1, 1, 1, 1, 0, utc) 
    5050        cursor = self.db.cursor() 
    5151        cursor.execute("INSERT INTO wiki VALUES(%s,%s,%s,%s,%s,%s,%s,%s)", 
    52                        ('TestPage', 0, to_timestamp(t), 'joe', '::1', 'Bla bla', 
     52                       ('TestPage', 0, to_utimestamp(t), 'joe', '::1', 'Bla bla', 
    5353                        'Testing', 0)) 
    5454 
    5555        page = WikiPage(self.env, 'TestPage') 
     
    7171        cursor = self.db.cursor() 
    7272        cursor.execute("SELECT version,time,author,ipnr,text,comment," 
    7373                       "readonly FROM wiki WHERE name=%s", ('TestPage',)) 
    74         self.assertEqual((1, to_timestamp(t), 'joe', '::1', 'Bla bla', 'Testing', 0), 
     74        self.assertEqual((1, to_utimestamp(t), 'joe', '::1', 'Bla bla', 'Testing', 0), 
    7575                         cursor.fetchone()) 
    7676 
    7777        listener = TestWikiChangeListener(self.env) 
     
    8282        t = datetime(2001, 1, 1, 1, 1, 1, 0, utc) 
    8383        t2 = datetime(2002, 1, 1, 1, 1, 1, 0, utc) 
    8484        cursor.execute("INSERT INTO wiki VALUES(%s,%s,%s,%s,%s,%s,%s,%s)", 
    85                        ('TestPage', 1, to_timestamp(t), 'joe', '::1', 'Bla bla', 
     85                       ('TestPage', 1, to_utimestamp(t), 'joe', '::1', 'Bla bla', 
    8686                        'Testing', 0)) 
    8787 
    8888        page = WikiPage(self.env, 'TestPage') 
     
    9292 
    9393        cursor.execute("SELECT version,time,author,ipnr,text,comment," 
    9494                       "readonly FROM wiki WHERE name=%s", ('TestPage',)) 
    95         self.assertEqual((1, to_timestamp(t), 'joe', '::1', 'Bla bla', 'Testing', 0), 
     95        self.assertEqual((1, to_utimestamp(t), 'joe', '::1', 'Bla bla', 'Testing', 0), 
    9696                         cursor.fetchone()) 
    97         self.assertEqual((2, to_timestamp(t2), 'kate', '192.168.0.101', 'Bla', 
     97        self.assertEqual((2, to_utimestamp(t2), 'kate', '192.168.0.101', 'Bla', 
    9898                          'Changing', 0), cursor.fetchone()) 
    9999 
    100100        listener = TestWikiChangeListener(self.env) 
  • trac/wiki/web_ui.py

    diff --git a/trac/wiki/web_ui.py b/trac/wiki/web_ui.py
    a b  
    1616# Author: Jonas Borgström <jonas@edgewall.com> 
    1717#         Christopher Lenz <cmlenz@gmx.de> 
    1818 
    19 from datetime import datetime 
    2019import pkg_resources 
    2120import re 
    2221 
     
    3130from trac.search import ISearchSource, search_to_sql, shorten_result 
    3231from trac.timeline.api import ITimelineEventProvider 
    3332from trac.util import get_reporter_id 
    34 from trac.util.datefmt import to_timestamp, utc 
     33from trac.util.datefmt import from_utimestamp, to_utimestamp 
    3534from trac.util.text import shorten_line 
    3635from trac.util.translation import _ 
    3736from trac.versioncontrol.diff import get_diff_options, diff_blocks 
     
    608607            cursor = db.cursor() 
    609608            cursor.execute("SELECT time,name,comment,author,version " 
    610609                           "FROM wiki WHERE time>=%s AND time<=%s", 
    611                            (to_timestamp(start), to_timestamp(stop))) 
     610                           (to_utimestamp(start), to_utimestamp(stop))) 
    612611            for ts, name, comment, author, version in cursor: 
    613612                wiki_page = wiki_realm(id=name, version=version) 
    614613                if 'WIKI_VIEW' not in req.perm(wiki_page): 
    615614                    continue 
    616                 yield ('wiki', datetime.fromtimestamp(ts, utc), author, 
     615                yield ('wiki', from_utimestamp(ts), author, 
    617616                       (wiki_page, comment)) 
    618617 
    619618            # Attachments 
     
    664663            if 'WIKI_VIEW' in req.perm(page): 
    665664                yield (get_resource_url(self.env, page, req.href), 
    666665                       '%s: %s' % (name, shorten_line(text)), 
    667                        datetime.fromtimestamp(ts, utc), author, 
     666                       from_utimestamp(ts), author, 
    668667                       shorten_result(text, terms)) 
    669668         
    670669        # Attachments