Edgewall Software

Ticket #6466: 6466-microsecond-times-9198.patch

File 6466-microsecond-times-9198.patch, 79.1 KB (added by rblank, 2 years ago)

Updated patch for current trunk (post multirepos and transaction merges).

  • 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 
     
    3736from trac.resource import * 
    3837from trac.search import search_to_sql, shorten_result 
    3938from trac.util import get_reporter_id, create_unique_file 
    40 from trac.util.datefmt import format_datetime, to_timestamp, utc 
     39from trac.util.datefmt import format_datetime, from_utimestamp, \ 
     40                              to_datetime, to_utimestamp, utc 
    4141from trac.util.text import exception_to_unicode, pretty_size, print_table, \ 
    4242                           unicode_quote, unicode_unquote 
    4343from trac.util.translation import _ 
     
    151151        self.filename = row[0] 
    152152        self.description = row[1] 
    153153        self.size = row[2] and int(row[2]) or 0 
    154         time = row[3] and int(row[3]) or 0 
    155         self.date = datetime.fromtimestamp(time, utc) 
     154        self.date = from_utimestamp(row[3]) 
    156155        self.author = row[4] 
    157156        self.ipnr = row[5] 
    158157 
     
    195194 
    196195 
    197196    def insert(self, filename, fileobj, size, t=None, db=None): 
    198         # FIXME: `t` should probably be switched to `datetime` too 
    199  
    200197        self.size = size and int(size) or 0 
    201         timestamp = int(t or time.time()) 
    202         self.date = datetime.fromtimestamp(timestamp, utc) 
     198        if t is None: 
     199            t = datetime.now(utc) 
     200        elif not isinstance(t, datetime): # Compatibility with 0.11 
     201            t = to_datetime(t, utc) 
     202        self.date = t 
    203203 
    204204        # Make sure the path to the attachment is inside the environment 
    205205        # attachments directory 
     
    225225                cursor.execute("INSERT INTO attachment " 
    226226                               "VALUES (%s,%s,%s,%s,%s,%s,%s,%s)", 
    227227                               (self.parent_realm, self.parent_id, filename, 
    228                                 self.size, timestamp, self.description, 
     228                                self.size, to_utimestamp(t), self.description, 
    229229                                self.author, self.ipnr)) 
    230230                shutil.copyfileobj(fileobj, targetfile) 
    231231                self.resource.id = self.filename = filename 
     
    252252            attachment.filename = filename 
    253253            attachment.description = description 
    254254            attachment.size = size and int(size) or 0 
    255             time = time and int(time) or 0 
    256             attachment.date = datetime.fromtimestamp(time, utc) 
     255            attachment.date = from_utimestamp(time or 0) 
    257256            attachment.author = author 
    258257            attachment.ipnr = ipnr 
    259258            yield attachment 
     
    439438                       "  FROM attachment " 
    440439                       "  WHERE time > %s AND time < %s " 
    441440                       "        AND type = %s", 
    442                        (to_timestamp(start), to_timestamp(stop), realm)) 
     441                       (to_utimestamp(start), to_utimestamp(stop), realm)) 
    443442        for realm, id, filename, ts, description, author in cursor: 
    444             time = datetime.fromtimestamp(ts, utc) 
     443            time = from_utimestamp(ts) 
    445444            yield ('created', realm, id, filename, time, description, author) 
    446445 
    447446    def get_timeline_events(self, req, resource_realm, start, stop): 
     
    489488            if 'ATTACHMENT_VIEW' in req.perm(attachment): 
    490489                yield (get_resource_url(self.env, attachment, req.href), 
    491490                       get_resource_shortname(self.env, attachment), 
    492                        datetime.fromtimestamp(time, utc), author, 
     491                       from_utimestamp(time), author, 
    493492                       shorten_result(desc, terms)) 
    494493     
    495494    # 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    """Database connector for MySQL version 4.1 and greater. 
     
    134139        coldefs = [] 
    135140        for column in table.columns: 
    136141            ctype = column.type 
     142            ctype = _type_map.get(ctype, ctype) 
    137143            if column.auto_increment: 
    138144                ctype = 'INT UNSIGNED NOT NULL AUTO_INCREMENT' 
    139145                # Override the column type, as a text field cannot 
     
    152158                  '_'.join(index.columns), table.name, 
    153159                  self._collist(table, index.columns)) 
    154160 
     161    def alter_column_types(self, table, columns): 
     162        """Yield SQL statements altering the type of one or more columns of 
     163        a table. 
     164         
     165        Type changes are specified as a `columns` dict mapping column names 
     166        to `(from, to)` SQL type tuples. 
     167        """ 
     168        alterations = [] 
     169        for name, (from_, to) in sorted(columns.iteritems()): 
     170            to = _type_map.get(to, to) 
     171            if to != _type_map.get(from_, from_): 
     172                alterations.append((name, to)) 
     173        if alterations: 
     174            yield "ALTER TABLE %s %s" % (table, 
     175                ', '.join("MODIFY %s %s" % each 
     176                          for each in alterations)) 
     177 
    155178    def backup(self, dest_file): 
    156179        try: 
    157180            from subprocess import Popen, PIPE 
     
    204227        self._is_closed = False 
    205228 
    206229    def cast(self, column, type): 
    207         if type == 'int': 
     230        if type == 'int'or type == 'int64': 
    208231            type = 'signed' 
    209232        elif type == 'text': 
    210233            type = 'char' 
  • 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    """Database connector for PostgreSQL. 
     
    97102        coldefs = [] 
    98103        for column in table.columns: 
    99104            ctype = column.type 
     105            ctype = _type_map.get(ctype, ctype) 
    100106            if column.auto_increment: 
    101107                ctype = 'SERIAL' 
    102             if len(table.key) == 1 and column.name in table.key: 
     108            elif len(table.key) == 1 and column.name in table.key: 
    103109                ctype += ' PRIMARY KEY' 
    104110            coldefs.append('    "%s" %s' % (column.name, ctype)) 
    105111        if len(table.key) > 1: 
     
    114120                     '_'.join(index.columns), table.name, 
    115121                     '","'.join(index.columns)) 
    116122 
     123    def alter_column_types(self, table, columns): 
     124        """Yield SQL statements altering the type of one or more columns of 
     125        a table. 
     126         
     127        Type changes are specified as a `columns` dict mapping column names 
     128        to `(from, to)` SQL type tuples. 
     129        """ 
     130        alterations = [] 
     131        for name, (from_, to) in sorted(columns.iteritems()): 
     132            to = _type_map.get(to, to) 
     133            if to != _type_map.get(from_, from_): 
     134                alterations.append((name, to)) 
     135        if alterations: 
     136            yield "ALTER TABLE %s %s" % (table, 
     137                ', '.join("ALTER COLUMN %s TYPE %s" % each 
     138                          for each in alterations)) 
     139 
    117140    def backup(self, dest_file): 
    118141        try: 
    119142            from subprocess import Popen, PIPE 
     
    191214 
    192215    def cast(self, column, type): 
    193216        # Temporary hack needed for the union of selects in the search module 
    194         return 'CAST(%s AS %s)' % (column, type) 
     217        return 'CAST(%s AS %s)' % (column, _type_map.get(type, type)) 
    195218 
    196219    def concat(self, *args): 
    197220        return '||'.join(args) 
  • trac/db/sqlite_backend.py

    diff --git a/trac/db/sqlite_backend.py b/trac/db/sqlite_backend.py
    a b  
    101101            return result 
    102102 
    103103 
     104# Mapping from "abstract" SQL types to DB-specific types 
     105_type_map = { 
     106    'int': 'integer', 
     107    'int64': 'integer', 
     108} 
     109 
     110 
    104111def _to_sql(table): 
    105112    sql = ["CREATE TABLE %s (" % table.name] 
    106113    coldefs = [] 
    107114    for column in table.columns: 
    108115        ctype = column.type.lower() 
     116        ctype = _type_map.get(ctype, ctype) 
    109117        if column.auto_increment: 
    110118            ctype = "integer PRIMARY KEY" 
    111119        elif len(table.key) == 1 and column.name in table.key: 
    112120            ctype += " PRIMARY KEY" 
    113         elif ctype == "int": 
    114             ctype = "integer" 
    115121        coldefs.append("    %s %s" % (column.name, ctype)) 
    116122    if len(table.key) > 1: 
    117123        coldefs.append("    UNIQUE (%s)" % ','.join(table.key)) 
     
    187193    def to_sql(self, table): 
    188194        return _to_sql(table) 
    189195 
     196    def alter_column_types(self, table, columns): 
     197        """Yield SQL statements altering the type of one or more columns of 
     198        a table. 
     199         
     200        Type changes are specified as a `columns` dict mapping column names 
     201        to `(from, to)` SQL type tuples. 
     202        """ 
     203        for name, (from_, to) in sorted(columns.iteritems()): 
     204            if _type_map.get(to, to) != _type_map.get(from_, from_): 
     205                raise NotImplementedError('Conversion from %s to %s is not ' 
     206                                          'implemented' % (from_, to)) 
     207        return () 
     208 
    190209    def backup(self, dest_file): 
    191210        """Simple SQLite-specific backup of the database. 
    192211 
     
    204223            raise TracError("Backup attempt failed") 
    205224        return dest_file 
    206225 
     226 
    207227class SQLiteConnection(ConnectionWrapper): 
    208228    """Connection wrapper for SQLite.""" 
    209229 
     
    260280 
    261281    def cast(self, column, type): 
    262282        if sqlite_version >= 30203: 
    263             return 'CAST(%s AS %s)' % (column, type) 
     283            return 'CAST(%s AS %s)' % (column, _type_map.get(type, type)) 
    264284        elif type == 'int': 
    265285            # hack to force older SQLite versions to convert column to an int 
    266286            return '1*' + column 
  • 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 = 24 
     20db_version = 25 
    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'), 
     
    9292    Table('revision', key=('repos', 'rev'))[ 
    9393        Column('repos', type='int'), 
    9494        Column('rev'), 
    95         Column('time', type='int'), 
     95        Column('time', type='int64'), 
    9696        Column('author'), 
    9797        Column('message'), 
    9898        Index(['repos', 'time'])], 
     
    110110    Table('ticket', key='id')[ 
    111111        Column('id', auto_increment=True), 
    112112        Column('type'), 
    113         Column('time', type='int'), 
    114         Column('changetime', type='int'), 
     113        Column('time', type='int64'), 
     114        Column('changetime', type='int64'), 
    115115        Column('component'), 
    116116        Column('severity'), 
    117117        Column('priority'), 
     
    129129        Index(['status'])],     
    130130    Table('ticket_change', key=('ticket', 'time', 'field'))[ 
    131131        Column('ticket', type='int'), 
    132         Column('time', type='int'), 
     132        Column('time', type='int64'), 
    133133        Column('author'), 
    134134        Column('field'), 
    135135        Column('oldvalue'), 
     
    150150        Column('description')], 
    151151    Table('milestone', key='name')[ 
    152152        Column('name'), 
    153         Column('due', type='int'), 
    154         Column('completed', type='int'), 
     153        Column('due', type='int64'), 
     154        Column('completed', type='int64'), 
    155155        Column('description')], 
    156156    Table('version', key='name')[ 
    157157        Column('name'), 
    158         Column('time', type='int'), 
     158        Column('time', type='int64'), 
    159159        Column('description')], 
    160160 
    161161    # Report system 
  • trac/ticket/model.py

    diff --git a/trac/ticket/model.py b/trac/ticket/model.py
    a b  
    2727from trac.ticket.api import TicketSystem 
    2828from trac.util import embedded_numbers, partition 
    2929from trac.util.text import empty 
    30 from trac.util.datefmt import utc, utcmax, to_timestamp 
     30from trac.util.datefmt import from_utimestamp, to_utimestamp, utc, utcmax 
    3131from trac.util.translation import _ 
    3232 
    3333__all__ = ['Ticket', 'Type', 'Status', 'Resolution', 'Priority', 'Severity', 
     
    109109        for i, field in enumerate(std_fields): 
    110110            value = row[i] 
    111111            if field in self.time_fields: 
    112                 self.values[field] = datetime.fromtimestamp(value or 0, utc) 
     112                self.values[field] = from_utimestamp(value) 
    113113            elif value is None: 
    114114                self.values[field] = empty 
    115115            else: 
     
    193193        values = dict(self.values) 
    194194        for field in self.time_fields: 
    195195            if field in values: 
    196                 values[field] = to_timestamp(values[field]) 
     196                values[field] = to_utimestamp(values[field]) 
    197197         
    198198        # Insert ticket record 
    199199        std_fields = [] 
     
    245245 
    246246        if when is None: 
    247247            when = datetime.now(utc) 
    248         when_ts = to_timestamp(when) 
     248        when_ts = to_utimestamp(when) 
    249249 
    250250        if 'component' in self.values: 
    251251            # If the component is changed on a 'new' ticket 
     
    359359        db = self._get_db(db) 
    360360        cursor = db.cursor() 
    361361        sid = str(self.id) 
    362         when_ts = when and to_timestamp(when) or 0 
     362        when_ts = to_utimestamp(when) 
    363363        if when_ts: 
    364364            cursor.execute("SELECT time,author,field,oldvalue,newvalue," 
    365365                           "1 AS permanent FROM ticket_change " 
     
    387387                           (self.id, sid, sid)) 
    388388        log = [] 
    389389        for t, author, field, oldvalue, newvalue, permanent in cursor: 
    390             log.append((datetime.fromtimestamp(int(t), utc), author, field, 
    391                        oldvalue or '', newvalue or '', permanent)) 
     390            log.append((from_utimestamp(t), author, field, 
     391                        oldvalue or '', newvalue or '', permanent)) 
    392392        return log 
    393393 
    394394    def delete(self, db=None): 
     
    417417                           "WHERE ticket=%s AND time=%s", 
    418418                           (self.id, ts)) 
    419419            fields = {} 
    420             change = {'date': datetime.fromtimestamp(int(ts), utc), 
     420            change = {'date': from_utimestamp(ts), 
    421421                      'author': author, 'fields': fields} 
    422422            for field, author, old, new in cursor: 
    423423                fields[field] = {'author': author, 'old': old, 'new': new} 
     
    427427        """Modify a ticket comment specified by its date, while keeping a 
    428428        history of edits. 
    429429        """ 
    430         ts = to_timestamp(cdate) 
     430        ts = to_utimestamp(cdate) 
    431431        if when is None: 
    432432            when = datetime.now(utc) 
    433         when_ts = to_timestamp(when) 
     433        when_ts = to_utimestamp(when) 
    434434 
    435435        @with_transaction(self.env, db) 
    436436        def do_modify(db): 
     
    494494            rows = sorted((int(field[8:]), author, old, new) 
    495495                          for field, author, old, new in cursor) 
    496496            for rev, author, comment, ts in rows: 
    497                 history.append((rev, datetime.fromtimestamp(int(ts0), utc), 
    498                                 author0, comment)) 
     497                history.append((rev, from_utimestamp(long(ts0)), author0, 
     498                                comment)) 
    499499                ts0, author0 = ts, author 
    500500            history.sort() 
    501501            rev = history and (history[-1][0] + 1) or 0 
    502             history.append((rev, datetime.fromtimestamp(int(ts0), utc), 
    503                             author0, last_comment)) 
     502            history.append((rev, from_utimestamp(long(ts0)), author0, 
     503                            last_comment)) 
    504504        return history 
    505505 
    506506    def _find_comment(self, cnum, db): 
     
    823823    def _from_database(self, row): 
    824824        name, due, completed, description = row 
    825825        self.name = name 
    826         self.due = due and datetime.fromtimestamp(int(due), utc) or None 
    827         self.completed = completed and \ 
    828                          datetime.fromtimestamp(int(completed), utc) or None 
     826        self.due = due and from_utimestamp(due) or None 
     827        self.completed = completed and from_utimestamp(completed) or None 
    829828        self.description = description or '' 
    830829        self._to_old() 
    831830 
     
    869868            cursor.execute("INSERT INTO milestone " 
    870869                           "(name,due,completed,description) " 
    871870                           "VALUES (%s,%s,%s,%s)", 
    872                            (self.name, to_timestamp(self.due), 
    873                             to_timestamp(self.completed), self.description)) 
     871                           (self.name, to_utimestamp(self.due), 
     872                            to_utimestamp(self.completed), self.description)) 
    874873            self._to_old() 
    875874            TicketSystem(self.env).reset_ticket_fields(db) 
    876875 
     
    888887            self.env.log.info('Updating milestone "%s"' % self.name) 
    889888            cursor.execute("UPDATE milestone SET name=%s,due=%s," 
    890889                           "completed=%s,description=%s WHERE name=%s", 
    891                            (self.name, to_timestamp(self.due), 
    892                             to_timestamp(self.completed), 
     890                           (self.name, to_utimestamp(self.due), 
     891                            to_utimestamp(self.completed), 
    893892                            self.description, self._old['name'])) 
    894893            self.env.log.info('Updating milestone field of all tickets ' 
    895894                              'associated with milestone "%s"' % self.name) 
     
    957956                raise ResourceNotFound(_('Version %(name)s does not exist.', 
    958957                                         name=name)) 
    959958            self.name = self._old_name = name 
    960             self.time = row[0] and datetime.fromtimestamp(int(row[0]), utc) \ 
    961                             or None 
     959            self.time = row[0] and from_utimestamp(row[0]) or None 
    962960            self.description = row[1] or '' 
    963961        else: 
    964962            self.name = self._old_name = None 
     
    990988            self.env.log.debug("Creating new version '%s'" % self.name) 
    991989            cursor.execute("INSERT INTO version (name,time,description) " 
    992990                           "VALUES (%s,%s,%s)", 
    993                            (self.name, to_timestamp(self.time), 
     991                           (self.name, to_utimestamp(self.time), 
    994992                            self.description)) 
    995993            self._old_name = self.name 
    996994            TicketSystem(self.env).reset_ticket_fields(db) 
     
    10071005            self.env.log.info('Updating version "%s"' % self.name) 
    10081006            cursor.execute("UPDATE version SET name=%s,time=%s,description=%s " 
    10091007                           "WHERE name=%s", 
    1010                            (self.name, to_timestamp(self.time), 
     1008                           (self.name, to_utimestamp(self.time), 
    10111009                            self.description, self._old_name)) 
    10121010            if self.name != self._old_name: 
    10131011                # Update tickets 
     
    10261024        for name, time, description in cursor: 
    10271025            version = cls(env) 
    10281026            version.name = version._old_name = name 
    1029             version.time = time and datetime.fromtimestamp(int(time), utc) \ 
    1030                                 or None 
     1027            version.time = time and from_utimestamp(time) or None 
    10311028            version.description = description or '' 
    10321029            versions.append(version) 
    10331030        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)) 
     
    468469        def get_timestamp(date): 
    469470            if date: 
    470471                try: 
    471                     return to_timestamp(parse_date(date, req.tz)) 
     472                    return to_utimestamp(parse_date(date, req.tz)) 
    472473                except TracError, e: 
    473474                    errors.append(unicode(e)) 
    474475            return None 
     
    486487                                    value.split(';', 1)] 
    487488                else: 
    488489                    (start, end) = (value.strip(), '') 
    489                 col_cast = db.cast(col, 'int') 
     490                col_cast = db.cast(col, 'int64') 
    490491                start = get_timestamp(start) 
    491492                end = get_timestamp(end) 
    492493                if start is not None and end is not 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 
     
    3130from trac.perm import IPermissionRequestor 
    3231from trac.resource import * 
    3332from trac.search import ISearchSource, search_to_sql, shorten_result 
    34 from trac.util.datefmt import parse_date, utc, to_timestamp, to_datetime, \ 
     33from trac.util.datefmt import parse_date, utc, to_utimestamp, \ 
    3534                              get_date_format_hint, get_datetime_format_hint, \ 
    36                               format_date, format_datetime 
     35                              format_date, format_datetime, from_utimestamp 
    3736from trac.util.text import CRLF 
    3837from trac.util.translation import _ 
    3938from trac.ticket import Milestone, Ticket, TicketSystem, group_milestones 
     
    476475                                   (ticket.id,)) 
    477476                    row = cursor.fetchone() 
    478477                    if row: 
    479                         write_utctime('COMPLETED', to_datetime(row[0], utc)) 
     478                        write_utctime('COMPLETED', from_utimestamp(row[0])) 
    480479                write_prop('END', 'VTODO') 
    481480        write_prop('END', 'VCALENDAR') 
    482481 
     
    531530            # TODO: creation and (later) modifications should also be reported 
    532531            cursor.execute("SELECT completed,name,description FROM milestone " 
    533532                           "WHERE completed>=%s AND completed<=%s", 
    534                            (to_timestamp(start), to_timestamp(stop))) 
     533                           (to_utimestamp(start), to_utimestamp(stop))) 
    535534            for completed, name, description in cursor: 
    536535                milestone = milestone_realm(id=name) 
    537536                if 'MILESTONE_VIEW' in req.perm(milestone): 
    538                     yield('milestone', datetime.fromtimestamp(completed, utc), 
     537                    yield('milestone', from_utimestamp(completed), 
    539538                          '', (milestone, description)) # FIXME: author? 
    540539 
    541540            # Attachments 
     
    866865        for name, due, completed, description in cursor: 
    867866            milestone = milestone_realm(id=name) 
    868867            if 'MILESTONE_VIEW' in req.perm(milestone): 
     868                dt = (completed and from_utimestamp(completed) or 
     869                      due and from_utimestamp(due) or datetime.now(utc)) 
    869870                yield (get_resource_url(self.env, milestone, req.href), 
    870                        get_resource_name(self.env, milestone), 
    871                        datetime.fromtimestamp( 
    872                            completed or due or time(), utc), 
     871                       get_resource_name(self.env, milestone), dt, 
    873872                       '', shorten_result(description, terms)) 
    874873         
    875874        # 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  
    147147 
    148148                        <!--! generic fields --> 
    149149                        <py:when test="col == 'time'"> 
    150                           <td class="date" py:attrs="td_attrs">${cell.value != '' and format_time(int(cell.value)) or '--'} 
     150                          <td class="date" py:attrs="td_attrs">${cell.value != '' and format_time(from_utimestamp(long(cell.value))) or '--'} 
    151151                            <hr py:if="fullrow"/> 
    152152                          </td> 
    153153                        </py:when> 
    154154 
    155155                        <py:when test="col in ('date', 'created', 'modified')"> 
    156                           <td class="date" py:attrs="td_attrs">${cell.value != '' and format_date(int(cell.value)) or '--'} 
     156                          <td class="date" py:attrs="td_attrs">${cell.value != '' and format_date(from_utimestamp(long(cell.value))) or '--'} 
    157157                            <hr py:if="fullrow"/> 
    158158                          </td> 
    159159                        </py:when> 
    160160 
    161161                        <py:when test="col == 'datetime'"> 
    162                           <td class="date" py:attrs="td_attrs">${cell.value != '' and format_datetime(int(cell.value)) or '--'} 
     162                          <td class="date" py:attrs="td_attrs">${cell.value != '' and format_datetime(from_utimestamp(long(cell.value))) or '--'} 
    163163                            <hr py:if="fullrow"/> 
    164164                          </td> 
    165165                        </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 IMilestoneChangeListener, ITicketChangeListener 
    66from trac.test import EnvironmentStub 
    7 from trac.util.datefmt import utc, to_timestamp 
     7from trac.util.datefmt import from_utimestamp, to_utimestamp, utc 
    88 
    99from datetime import datetime, timedelta 
    1010import unittest 
     
    296296                       "                        description,author,ipnr) " 
    297297                       "VALUES ('ticket',%s,'file.txt',1234,%s," 
    298298                       "        'My file','mark','')", 
    299                        (str(tkt_id), to_timestamp(t2))) 
     299                       (str(tkt_id), to_utimestamp(t2))) 
    300300        db.commit() 
    301301        t3 = datetime(2001, 1, 1, 1, 1, 3, 0, utc) 
    302302        ticket.save_changes('jim', 'Other', t3) 
     
    308308                          sorted(log[1:3])) 
    309309        self.assertEqual((t3, 'jim', 'comment', '2', 'Other', True), log[3]) 
    310310 
     311    def test_subsecond_change(self): 
     312        """Perform two ticket changes within a second.""" 
     313        tkt_id = self._insert_ticket('Test', reporter='joe', component='foo') 
     314        ticket = Ticket(self.env, tkt_id) 
     315        t1 = datetime(2001, 1, 1, 1, 1, 1, 123456, utc) 
     316        ticket.save_changes('jane', 'Testing', t1) 
     317        t2 = datetime(2001, 1, 1, 1, 1, 1, 123789, utc) 
     318        ticket.save_changes('jim', 'Other', t2) 
     319        log = ticket.get_changelog() 
     320        self.assertEqual(2, len(log)) 
     321        self.assertEqual((t1, 'jane', 'comment', '1', 'Testing', True), log[0]) 
     322        self.assertEqual((t2, 'jim', 'comment', '2', 'Other', True), log[1]) 
     323 
    311324    def test_changelog_with_reverted_change(self): 
    312325        tkt_id = self._insert_ticket('Test', reporter='joe', component='foo') 
    313326        ticket = Ticket(self.env, tkt_id) 
     
    387400     
    388401    def _find_comment(self, ticket, cnum): 
    389402        (ts, author, comment) = ticket._find_comment(cnum, self.db) 
    390         return datetime.fromtimestamp(ts, utc) 
     403        return from_utimestamp(ts) 
    391404     
    392405    def assertChange(self, ticket, cnum, date, author, **fields): 
    393406        change = ticket.get_change(cnum) 
     
    411424        self.assertChange(ticket, 1, self.t1, 'jack', 
    412425            comment=dict(author='jack', old='1', new='New comment 1'), 
    413426            _comment0=dict(author='joe', old='Comment 1', 
    414                            new=str(to_timestamp(t)))) 
     427                           new=str(to_utimestamp(t)))) 
    415428 
    416429    def test_threading(self): 
    417430        """Check modification of a "threaded" comment""" 
     
    423436            owner=dict(author='john', old='john', new='jack'), 
    424437            comment=dict(author='john', old='1.2', new='New comment 2'), 
    425438            _comment0=dict(author='joe', old='Comment 2', 
    426                            new=str(to_timestamp(t)))) 
     439                           new=str(to_utimestamp(t)))) 
    427440         
    428441    def test_modify_missing_cnum(self): 
    429442        """Editing a comment with no cnum in oldvalue""" 
     
    440453            keywords=dict(author='jim', old='a, b, c', new='a, b'), 
    441454            comment=dict(author='jim', old='', new='New comment 3'), 
    442455            _comment0=dict(author='joe', old='Comment 3', 
    443                            new=str(to_timestamp(t)))) 
     456                           new=str(to_utimestamp(t)))) 
    444457         
    445458    def test_modify_missing_comment(self): 
    446459        """Editing a comment where the comment field is missing""" 
     
    457470            owner=dict(author='john', old='john', new='jack'), 
    458471            comment=dict(author='john', old='', new='New comment 2'), 
    459472            _comment0=dict(author='joe', old='', 
    460                            new=str(to_timestamp(t)))) 
     473                           new=str(to_utimestamp(t)))) 
    461474         
    462475    def test_modify_missing_cnums_and_comment(self): 
    463476        """Editing a comments when all cnums are missing and one comment 
     
    481494            keywords=dict(author='jim', old='a, b, c', new='a, b'), 
    482495            comment=dict(author='jim', old='', new='New comment 3'), 
    483496            _comment0=dict(author='joe', old='Comment 3', 
    484                            new=str(to_timestamp(t)))) 
     497                           new=str(to_utimestamp(t)))) 
    485498 
    486499        # Modify missing comment 
    487500        t = self.created + timedelta(seconds=60) 
     
    491504            owner=dict(author='john', old='john', new='jack'), 
    492505            comment=dict(author='john', old='', new='New comment 2'), 
    493506            _comment0=dict(author='joe', old='', 
    494                            new=str(to_timestamp(t)))) 
     507                           new=str(to_utimestamp(t)))) 
    495508 
    496509    def test_missing_comment_edit(self): 
    497510        """Modify a comment where one edit is missing""" 
     
    506519        self.assertChange(ticket, 1, self.t1, 'jack', 
    507520            comment=dict(author='jack', old='1', new='Other comment 1'), 
    508521            _comment0=dict(author='joe', old='Comment 1', 
    509                            new=str(to_timestamp(t1))), 
     522                           new=str(to_utimestamp(t1))), 
    510523            _comment1=dict(author='joe', old='New comment 1', 
    511                            new=str(to_timestamp(t2)))) 
     524                           new=str(to_utimestamp(t2)))) 
    512525         
    513526        cursor = self.db.cursor() 
    514527        cursor.execute("DELETE FROM ticket_change " 
     
    522535        self.assertChange(ticket, 1, self.t1, 'jack', 
    523536            comment=dict(author='jack', old='1', new='Newest comment 1'), 
    524537            _comment1=dict(author='joe', old='New comment 1', 
    525                            new=str(to_timestamp(t2))), 
     538                           new=str(to_utimestamp(t2))), 
    526539            _comment2=dict(author='joe', old='Other comment 1', 
    527                            new=str(to_timestamp(t3)))) 
     540                           new=str(to_utimestamp(t3)))) 
    528541 
    529542    def test_comment_history(self): 
    530543        """Check the generation of the comment history""" 
     
    725738 
    726739        cursor = self.db.cursor() 
    727740        cursor.execute("SELECT * FROM milestone WHERE name='Test'") 
    728         self.assertEqual(('Test', to_timestamp(t1), to_timestamp(t2), 'Foo bar'), 
     741        self.assertEqual(('Test', to_utimestamp(t1), to_utimestamp(t2), 
     742                          'Foo bar'), 
    729743                         cursor.fetchone()) 
    730744 
    731745    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  
    362362  LEFT OUTER JOIN enum AS priority ON (priority.type='priority' AND priority.name=priority) 
    363363WHERE (((%(cast_time)s>=%%s AND %(cast_time)s<%%s))) 
    364364ORDER BY COALESCE(t.id,0)=0,t.id""" % { 
    365           'cast_time': self.env.get_db_cnx().cast('t.time', 'int')}) 
    366         self.assertEqual([1217548800, 1220227200], args) 
     365          'cast_time': self.env.get_db_cnx().cast('t.time', 'int64')}) 
     366        self.assertEqual([1217548800000000L, 1220227200000000L], args) 
    367367        tickets = query.execute(self.req) 
    368368 
    369369    def test_constrained_by_time_range_exclusion(self): 
     
    375375  LEFT OUTER JOIN enum AS priority ON (priority.type='priority' AND priority.name=priority) 
    376376WHERE ((NOT (%(cast_time)s>=%%s AND %(cast_time)s<%%s))) 
    377377ORDER BY COALESCE(t.id,0)=0,t.id""" % { 
    378           'cast_time': self.env.get_db_cnx().cast('t.time', 'int')}) 
    379         self.assertEqual([1217548800, 1220227200], args) 
     378          'cast_time': self.env.get_db_cnx().cast('t.time', 'int64')}) 
     379        self.assertEqual([1217548800000000L, 1220227200000000L], args) 
    380380        tickets = query.execute(self.req) 
    381381 
    382382    def test_constrained_by_time_range_open_right(self): 
     
    388388  LEFT OUTER JOIN enum AS priority ON (priority.type='priority' AND priority.name=priority) 
    389389WHERE ((%(cast_time)s>=%%s)) 
    390390ORDER BY COALESCE(t.id,0)=0,t.id""" % { 
    391           'cast_time': self.env.get_db_cnx().cast('t.time', 'int')}) 
    392         self.assertEqual([1217548800], args) 
     391          'cast_time': self.env.get_db_cnx().cast('t.time', 'int64')}) 
     392        self.assertEqual([1217548800000000L], args) 
    393393        tickets = query.execute(self.req) 
    394394 
    395395    def test_constrained_by_time_range_open_left(self): 
     
    401401  LEFT OUTER JOIN enum AS priority ON (priority.type='priority' AND priority.name=priority) 
    402402WHERE ((%(cast_time)s<%%s)) 
    403403ORDER BY COALESCE(t.id,0)=0,t.id""" % { 
    404           'cast_time': self.env.get_db_cnx().cast('t.time', 'int')}) 
    405         self.assertEqual([1220227200], args) 
     404          'cast_time': self.env.get_db_cnx().cast('t.time', 'int64')}) 
     405        self.assertEqual([1220227200000000L], args) 
    406406        tickets = query.execute(self.req) 
    407407 
    408408    def test_constrained_by_time_range_modified(self): 
     
    414414  LEFT OUTER JOIN enum AS priority ON (priority.type='priority' AND priority.name=priority) 
    415415WHERE (((%(cast_changetime)s>=%%s AND %(cast_changetime)s<%%s))) 
    416416ORDER BY COALESCE(t.id,0)=0,t.id""" % { 
    417           'cast_changetime': self.env.get_db_cnx().cast('t.changetime', 'int')}) 
    418         self.assertEqual([1217548800, 1220227200], args) 
     417          'cast_changetime': self.env.get_db_cnx().cast('t.changetime', 'int64')}) 
     418        self.assertEqual([1217548800000000L, 1220227200000000L], args) 
    419419        tickets = query.execute(self.req) 
    420420 
    421421    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 
     
    214215                           ': ', 
    215216                           ticketsystem.format_summary(summary, status, 
    216217                                                       resolution, type)), 
    217                        datetime.fromtimestamp(ts, utc), author, 
     218                       from_utimestamp(ts), author, 
    218219                       shorten_result(desc, terms)) 
    219220         
    220221        # Attachments 
     
    231232                yield ('ticket_details', _('Ticket updates'), False) 
    232233 
    233234    def get_timeline_events(self, req, start, stop, filters): 
    234         ts_start = to_timestamp(start) 
    235         ts_stop = to_timestamp(stop) 
     235        ts_start = to_utimestamp(start) 
     236        ts_stop = to_utimestamp(stop) 
    236237 
    237238        status_map = {'new': ('newticket', N_('created')), 
    238239                      'reopened': ('reopenedticket', N_('reopened')), 
     
    268269            else: 
    269270                return None 
    270271            kind, verb = status_map[status] 
    271             return (kind, datetime.fromtimestamp(ts, utc), author, 
     272            return (kind, from_utimestamp(ts), author, 
    272273                    (ticket, verb, info, summary, status, resolution, type, 
    273274                     description, comment, cid)) 
    274275 
     
    16461647                rev = int(field[8:]) 
    16471648                comment_history.setdefault(rev, {}).update({'comment': old}) 
    16481649                comment_history.setdefault(rev + 1, {}).update( 
    1649                         {'author': author, 
    1650                          'date': datetime.fromtimestamp(int(new), utc)}) 
     1650                        {'author': author, 'date': from_utimestamp(long(new))}) 
    16511651            elif old or new: 
    16521652                current['fields'][field] = {'old': old, 'new': new} 
    16531653        if current: 
  • trac/timeline/web_ui.py

    diff --git a/trac/timeline/web_ui.py b/trac/timeline/web_ui.py
    a b  
    2929from trac.perm import IPermissionRequestor 
    3030from trac.timeline.api import ITimelineEventProvider 
    3131from trac.util.datefmt import format_date, format_datetime, parse_date, \ 
    32                               to_timestamp, utc, pretty_timedelta 
     32                              to_utimestamp, utc, pretty_timedelta 
    3333from trac.util.text import exception_to_unicode, to_unicode 
    3434from trac.util.translation import _, tag_ 
    3535from trac.web import IRequestHandler, IRequestFilter 
     
    106106                precision = timedelta(hours=1) 
    107107            else: 
    108108                precision = None 
    109         fromdate = fromdate.replace(hour=23, minute=59, second=59) 
     109        fromdate = fromdate.replace(hour=23, minute=59, second=59, 
     110                                    microsecond=999999) 
    110111        try: 
    111112            daysback = int(req.args.get('daysback', '')) 
    112113        except ValueError: 
     
    312313                kind, date, author, data = event 
    313314            render = lambda field, context: \ 
    314315                    provider.render_timeline_event(context, field, event) 
    315         if isinstance(date, datetime): 
    316             dateuid = to_timestamp(date) 
    317         else: 
    318             dateuid = date 
     316        if not isinstance(date, datetime): 
    319317            date = datetime.fromtimestamp(date, utc) 
     318        dateuid = to_utimestamp(date) 
    320319        return {'kind': kind, 'author': author, 'date': date, 
    321320                'dateuid': dateuid, 'render': render, 'event': event, 
    322321                'data': data, 'provider': provider} 
  • 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/db25.py

    diff --git a/trac/upgrades/db25.py b/trac/upgrades/db25.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', 'int64'), 
     33                                       db.like()), 
     34                   ('_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  
    113113                         datefmt.format_date(a_date, format='%Y-%m-%d')) 
    114114 
    115115 
     116class UTimestampTestCase(unittest.TestCase): 
     117     
     118    def test_sub_second(self): 
     119        t = datetime.datetime(2001, 2, 3, 4, 5, 6, 123456, datefmt.utc) 
     120        ts = datefmt.to_utimestamp(t) 
     121        self.assertEqual(t, datefmt.from_utimestamp(ts)) 
     122 
     123 
    116124def suite(): 
    117125    suite = unittest.TestSuite() 
    118126    if PytzTestCase: 
     
    120128    else: 
    121129        print "SKIP: utils/tests/datefmt.py (no pytz installed)" 
    122130    suite.addTest(unittest.makeSuite(DateFormatTestCase)) 
     131    suite.addTest(unittest.makeSuite(UTimestampTestCase)) 
    123132    return suite 
    124133 
    125134if __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 
    1918 
    2019from trac.cache import CacheProxy 
    2120from trac.core import TracError 
    2221from trac.db.util import with_transaction 
    23 from trac.util.datefmt import utc, to_timestamp 
     22from trac.util.datefmt import from_utimestamp, to_utimestamp 
    2423from trac.util.translation import _ 
    2524from trac.versioncontrol import Changeset, Node, Repository, NoSuchChangeset 
    2625 
     
    7574        cursor.execute("SELECT rev FROM revision " 
    7675                       "WHERE repos=%s AND time >= %s AND time < %s " 
    7776                       "ORDER BY time DESC, rev DESC", 
    78                        (self.id, to_timestamp(start), 
    79                         to_timestamp(stop))) 
     77                       (self.id, to_utimestamp(start), to_utimestamp(stop))) 
    8078        for rev, in cursor: 
    8179            try: 
    8280                yield self.get_changeset(rev) 
     
    9593                WHERE repos=%s AND rev=%s 
    9694                """, (self.id, str(cset.rev))) 
    9795            for time, author, message in cursor: 
    98                 date = datetime.fromtimestamp(time, utc) 
    9996                old_cset[0] = Changeset(self.repos, cset.rev, message, author, 
    100                                         date) 
     97                                        from_utimestamp(time)) 
    10198            cursor.execute(""" 
    10299                UPDATE revision SET time=%s, author=%s, message=%s 
    103100                WHERE repos=%s AND rev=%s 
    104                 """, (to_timestamp(cset.date), cset.author, cset.message, 
     101                """, (to_utimestamp(cset.date), cset.author, cset.message, 
    105102                      self.id, str(cset.rev))) 
    106103        return old_cset[0] 
    107104         
     
    237234                            (repos,rev,time,author,message) 
    238235                        VALUES (%s,%s,%s,%s,%s) 
    239236                        """, (self.id, str(next_youngest), 
    240                               to_timestamp(cset.date), 
     237                              to_utimestamp(cset.date), 
    241238                              cset.author, cset.message)) 
    242239                except Exception, e: # *another* 1.1. resync attempt won  
    243240                    self.log.warning('Revision %s already cached: %r', 
     
    403400        row = cursor.fetchone() 
    404401        if row: 
    405402            _date, author, message = row 
    406             date = datetime.fromtimestamp(_date, utc) 
     403            date = from_utimestamp(_date) 
    407404            Changeset.__init__(self, repos, rev, message, author, date) 
    408405        else: 
    409406            raise NoSuchChangeset(rev) 
  • trac/versioncontrol/svn_fs.py

    diff --git a/trac/versioncontrol/svn_fs.py b/trac/versioncontrol/svn_fs.py
    a b  
    4646import os.path 
    4747import weakref 
    4848import posixpath 
    49 from datetime import datetime 
    5049 
    5150from trac.config import ListOption 
    5251from trac.core import * 
     
    5756from trac.util import embedded_numbers 
    5857from trac.util.text import exception_to_unicode, to_unicode 
    5958from trac.util.translation import _ 
    60 from trac.util.datefmt import utc 
     59from trac.util.datefmt import from_utimestamp 
    6160 
    6261 
    6362application_pool = None 
     
    780779                                 core.SVN_PROP_REVISION_DATE, self.pool()) 
    781780        if not _date: 
    782781            return None 
    783         ts = core.svn_time_from_cstring(_date, self.pool()) / 1000000 
    784         return datetime.fromtimestamp(ts, utc) 
     782        return from_utimestamp(core.svn_time_from_cstring(_date, self.pool())) 
    785783 
    786784    def _get_prop(self, name): 
    787785        return fs.node_prop(self.root, self._scoped_path_utf8, name, 
     
    845843        author = author and to_unicode(author, 'utf-8') 
    846844        _date = self._get_prop(core.SVN_PROP_REVISION_DATE) 
    847845        if _date: 
    848             ts = core.svn_time_from_cstring(_date, self.pool()) / 1000000 
    849             date = datetime.fromtimestamp(ts, utc) 
     846            ts = core.svn_time_from_cstring(_date, self.pool()) 
     847            date = from_utimestamp(ts) 
    850848        else: 
    851849            date = None 
    852850        Changeset.__init__(self, repos, 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  
    1717from datetime import datetime 
    1818 
    1919from trac.test import EnvironmentStub, Mock 
    20 from trac.util.datefmt import to_timestamp, utc 
     20from trac.util.datefmt import to_utimestamp, utc 
    2121from trac.versioncontrol import Repository, Changeset, Node, NoSuchChangeset 
    2222from trac.versioncontrol.cache import CachedRepository 
    2323 
     
    102102 
    103103        cursor = self.db.cursor() 
    104104        cursor.execute("SELECT rev,time,author,message FROM revision") 
    105         self.assertEquals(('0', to_timestamp(t1), '', ''), cursor.fetchone()) 
    106         self.assertEquals(('1', to_timestamp(t2), 'joe', 'Import'), 
     105        self.assertEquals(('0', to_utimestamp(t1), '', ''), cursor.fetchone()) 
     106        self.assertEquals(('1', to_utimestamp(t2), 'joe', 'Import'), 
    107107                          cursor.fetchone()) 
    108108        self.assertEquals(None, cursor.fetchone()) 
    109109        cursor.execute(""" 
     
    121121        t2 = datetime(2002, 1, 1, 1, 1, 1, 0, utc) 
    122122        t3 = datetime(2003, 1, 1, 1, 1, 1, 0, utc) 
    123123        self.preset_cache( 
    124             (('0', to_timestamp(t1), '', ''), []), 
    125             (('1', to_timestamp(t2), 'joe', 'Import'), 
     124            (('0', to_utimestamp(t1), '', ''), []), 
     125            (('1', to_utimestamp(t2), 'joe', 'Import'), 
    126126             [('trunk', 'D', 'A', None, None), 
    127127              ('trunk/README', 'F', 'A', None, None)]), 
    128128            ) 
     
    143143        cursor.execute(""" 
    144144            SELECT time,author,message FROM revision WHERE rev='2' 
    145145            """) 
    146         self.assertEquals((to_timestamp(t3), 'joe', 'Update'), 
     146        self.assertEquals((to_utimestamp(t3), 'joe', 'Update'), 
    147147                          cursor.fetchone()) 
    148148        self.assertEquals(None, cursor.fetchone()) 
    149149        cursor.execute(""" 
     
    159159        t2 = datetime(2002, 1, 1, 1, 1, 1, 0, utc) 
    160160        t3 = datetime(2003, 1, 1, 1, 1, 1, 0, utc) 
    161161        self.preset_cache( 
    162             (('0', to_timestamp(t1), '', ''), []), 
    163             (('1', to_timestamp(t2), 'joe', 'Import'), 
     162            (('0', to_utimestamp(t1), '', ''), []), 
     163            (('1', to_utimestamp(t2), 'joe', 'Import'), 
    164164             [('trunk', 'D', 'A', None, None), 
    165165              ('trunk/README', 'F', 'A', None, None)]), 
    166166            ) 
     
    183183 
    184184        cursor = self.db.cursor() 
    185185        cursor.execute("SELECT time,author,message FROM revision") 
    186         self.assertEquals((to_timestamp(t1), 'joe', '**empty**'), 
     186        self.assertEquals((to_utimestamp(t1), 'joe', '**empty**'), 
    187187                          cursor.fetchone()) 
    188         self.assertEquals((to_timestamp(t2), 'joe', 'Initial Import'), 
     188        self.assertEquals((to_utimestamp(t2), 'joe', 'Initial Import'), 
    189189                          cursor.fetchone()) 
    190         self.assertEquals((to_timestamp(t3), 'joe', 'Update'), 
     190        self.assertEquals((to_utimestamp(t3), 'joe', 'Update'), 
    191191                          cursor.fetchone()) 
    192192        self.assertEquals(None, cursor.fetchone()) 
    193193        cursor.execute(""" 
     
    206206        t1 = datetime(2001, 1, 1, 1, 1, 1, 0, utc) 
    207207        t2 = datetime(2002, 1, 1, 1, 1, 1, 0, utc) 
    208208        self.preset_cache( 
    209             (('0', to_timestamp(t1), '', ''), []), 
    210             (('1', to_timestamp(t2), 'joe', 'Import'), 
     209            (('0', to_utimestamp(t1), '', ''), []), 
     210            (('1', to_utimestamp(t2), 'joe', 'Import'), 
    211211             [('trunk', 'D', 'A', None, None), 
    212212              ('trunk/README', 'F', 'A', None, None)]), 
    213213            ) 
     
    226226 
    227227        cursor = self.db.cursor() 
    228228        cursor.execute("SELECT time,author,message FROM revision ORDER BY rev") 
    229         self.assertEquals((to_timestamp(t1), 'joe', '**empty**'), 
     229        self.assertEquals((to_utimestamp(t1), 'joe', '**empty**'), 
    230230                          cursor.fetchone()) 
    231         self.assertEquals((to_timestamp(t2), 'joe', 'Import'), 
     231        self.assertEquals((to_utimestamp(t2), 'joe', 'Import'), 
    232232                          cursor.fetchone()) 
    233233        self.assertEquals(None, cursor.fetchone()) 
    234234 
     
    236236        t1 = datetime(2001, 1, 1, 1, 1, 1, 0, utc) 
    237237        t2 = datetime(2002, 1, 1, 1, 1, 1, 0, utc) 
    238238        self.preset_cache( 
    239             (('0', to_timestamp(t1), '', ''), []), 
    240             (('1', to_timestamp(t2), 'joe', 'Import'), 
     239            (('0', to_utimestamp(t1), '', ''), []), 
     240            (('1', to_utimestamp(t2), 'joe', 'Import'), 
    241241             [('trunk', 'D', 'A', None, None), 
    242242              ('trunk/RDME', 'F', 'A', None, None)]), 
    243243            ) 
  • trac/versioncontrol/tests/svn_fs.py

    diff --git a/trac/versioncontrol/tests/svn_fs.py b/trac/versioncontrol/tests/svn_fs.py
    a b  
    146146        self.assertEqual(u'/tête', node.path) 
    147147        self.assertEqual(Node.DIRECTORY, node.kind) 
    148148        self.assertEqual(HEAD, node.rev) 
    149         self.assertEqual(datetime(2007, 4, 30, 17, 45, 26, 0, utc), 
     149        self.assertEqual(datetime(2007, 4, 30, 17, 45, 26, 234375, utc), 
    150150                         node.last_modified) 
    151151        node = self.repos.get_node(u'/tête/README.txt') 
    152152        self.assertEqual('README.txt', node.name) 
    153153        self.assertEqual(u'/tête/README.txt', node.path) 
    154154        self.assertEqual(Node.FILE, node.kind) 
    155155        self.assertEqual(3, node.rev) 
    156         self.assertEqual(datetime(2005, 4, 1, 13, 24, 58, 0, utc), node.last_modified) 
     156        self.assertEqual(datetime(2005, 4, 1, 13, 24, 58, 234643, utc), node.last_modified) 
    157157 
    158158    def test_get_node_specific_rev(self): 
    159159        node = self.repos.get_node(u'/tête', 1) 
     
    161161        self.assertEqual(u'/tête', node.path) 
    162162        self.assertEqual(Node.DIRECTORY, node.kind) 
    163163        self.assertEqual(1, node.rev) 
    164         self.assertEqual(datetime(2005, 4, 1, 10, 0, 52, 0, utc), node.last_modified) 
     164        self.assertEqual(datetime(2005, 4, 1, 10, 0, 52, 353248, utc), node.last_modified) 
    165165        node = self.repos.get_node(u'/tête/README.txt', 2) 
    166166        self.assertEqual('README.txt', node.name) 
    167167        self.assertEqual(u'/tête/README.txt', node.path) 
    168168        self.assertEqual(Node.FILE, node.kind) 
    169169        self.assertEqual(2, node.rev) 
    170         self.assertEqual(datetime(2005, 4, 1, 13, 12, 18, 0, utc), node.last_modified) 
     170        self.assertEqual(datetime(2005, 4, 1, 13, 12, 18, 216267, utc), node.last_modified) 
    171171 
    172172    def test_get_dir_entries(self): 
    173173        node = self.repos.get_node(u'/tête') 
     
    384384        self.assertEqual(0, chgset.rev) 
    385385        self.assertEqual('', chgset.message) 
    386386        self.assertEqual('', chgset.author) 
    387         self.assertEqual(datetime(2005, 4, 1, 9, 57, 41, 0, utc), chgset.date) 
     387        self.assertEqual(datetime(2005, 4, 1, 9, 57, 41, 312767, utc), chgset.date) 
    388388        self.assertRaises(StopIteration, chgset.get_changes().next) 
    389389 
    390390    def test_changeset_added_dirs(self): 
     
    392392        self.assertEqual(1, chgset.rev) 
    393393        self.assertEqual('Initial directory layout.', chgset.message) 
    394394        self.assertEqual('john', chgset.author) 
    395         self.assertEqual(datetime(2005, 4, 1, 10, 0, 52, 0, utc), chgset.date) 
     395        self.assertEqual(datetime(2005, 4, 1, 10, 0, 52, 353248, utc), chgset.date) 
    396396 
    397397        changes = chgset.get_changes() 
    398398        self.assertEqual(('branches', Node.DIRECTORY, Changeset.ADD, None, -1), 
     
    408408        self.assertEqual(3, chgset.rev) 
    409409        self.assertEqual('Fixed README.\n', chgset.message) 
    410410        self.assertEqual('kate', chgset.author) 
    411         self.assertEqual(datetime(2005, 4, 1, 13, 24, 58, 0, utc), chgset.date) 
     411        self.assertEqual(datetime(2005, 4, 1, 13, 24, 58, 234643, utc), chgset.date) 
    412412 
    413413        changes = chgset.get_changes() 
    414414        self.assertEqual((u'tête/README.txt', Node.FILE, Changeset.EDIT, 
     
    420420        self.assertEqual(5, chgset.rev) 
    421421        self.assertEqual('Moved directories.', chgset.message) 
    422422        self.assertEqual('kate', chgset.author) 
    423         self.assertEqual(datetime(2005, 4, 1, 16, 25, 39, 0, utc), chgset.date) 
     423        self.assertEqual(datetime(2005, 4, 1, 16, 25, 39, 658099, utc), chgset.date) 
    424424 
    425425        changes = chgset.get_changes() 
    426426        self.assertEqual((u'tête/dir1/dir2', Node.DIRECTORY, Changeset.MOVE, 
     
    434434        self.assertEqual(6, chgset.rev) 
    435435        self.assertEqual('More things to read', chgset.message) 
    436436        self.assertEqual('john', chgset.author) 
    437         self.assertEqual(datetime(2005, 4, 1, 18, 56, 46, 0, utc), chgset.date) 
     437        self.assertEqual(datetime(2005, 4, 1, 18, 56, 46, 985846, utc), chgset.date) 
    438438 
    439439        changes = chgset.get_changes() 
    440440        self.assertEqual((u'tête/README2.txt', Node.FILE, Changeset.COPY, 
     
    552552        self.assertEqual('/dir1', node.path) 
    553553        self.assertEqual(Node.DIRECTORY, node.kind) 
    554554        self.assertEqual(5, node.rev) 
    555         self.assertEqual(datetime(2005, 4, 1, 16, 25, 39, 0, utc), node.last_modified) 
     555        self.assertEqual(datetime(2005, 4, 1, 16, 25, 39, 658099, utc), node.last_modified) 
    556556        node = self.repos.get_node('/README.txt') 
    557557        self.assertEqual('README.txt', node.name) 
    558558        self.assertEqual('/README.txt', node.path) 
    559559        self.assertEqual(Node.FILE, node.kind) 
    560560        self.assertEqual(3, node.rev) 
    561         self.assertEqual(datetime(2005, 4, 1, 13, 24, 58, 0, utc), node.last_modified) 
     561        self.assertEqual(datetime(2005, 4, 1, 13, 24, 58, 234643, utc), node.last_modified) 
    562562 
    563563    def test_get_node_specific_rev(self): 
    564564        node = self.repos.get_node('/dir1', 4) 
     
    566566        self.assertEqual('/dir1', node.path) 
    567567        self.assertEqual(Node.DIRECTORY, node.kind) 
    568568        self.assertEqual(4, node.rev) 
    569         self.assertEqual(datetime(2005, 4, 1, 15, 42, 35, 0, utc), node.last_modified) 
     569        self.assertEqual(datetime(2005, 4, 1, 15, 42, 35, 450595, utc), node.last_modified) 
    570570        node = self.repos.get_node('/README.txt', 2) 
    571571        self.assertEqual('README.txt', node.name) 
    572572        self.assertEqual('/README.txt', node.path) 
    573573        self.assertEqual(Node.FILE, node.kind) 
    574574        self.assertEqual(2, node.rev) 
    575         self.assertEqual(datetime(2005, 4, 1, 13, 12, 18, 0, utc), node.last_modified) 
     575        self.assertEqual(datetime(2005, 4, 1, 13, 12, 18, 216267, utc), node.last_modified) 
    576576 
    577577    def test_get_dir_entries(self): 
    578578        node = self.repos.get_node('/') 
     
    677677        self.assertEqual(0, chgset.rev) 
    678678        self.assertEqual('', chgset.message) 
    679679        self.assertEqual('', chgset.author) 
    680         self.assertEqual(datetime(2005, 4, 1, 9, 57, 41, 0, utc), chgset.date) 
     680        self.assertEqual(datetime(2005, 4, 1, 9, 57, 41, 312767, utc), chgset.date) 
    681681        self.assertRaises(StopIteration, chgset.get_changes().next) 
    682682 
    683683    def test_changeset_added_dirs(self): 
     
    685685        self.assertEqual(4, chgset.rev) 
    686686        self.assertEqual('More directories.', chgset.message) 
    687687        self.assertEqual('john', chgset.author) 
    688         self.assertEqual(datetime(2005, 4, 1, 15, 42, 35, 0, utc), chgset.date) 
     688        self.assertEqual(datetime(2005, 4, 1, 15, 42, 35, 450595, utc), chgset.date) 
    689689 
    690690        changes = chgset.get_changes() 
    691691        self.assertEqual(('dir1', Node.DIRECTORY, 'add', None, -1), 
     
    701701        self.assertEqual(3, chgset.rev) 
    702702        self.assertEqual('Fixed README.\n', chgset.message) 
    703703        self.assertEqual('kate', chgset.author) 
    704         self.assertEqual(datetime(2005, 4, 1, 13, 24, 58, 0, utc), chgset.date) 
     704        self.assertEqual(datetime(2005, 4, 1, 13, 24, 58, 234643, utc), chgset.date) 
    705705 
    706706        changes = chgset.get_changes() 
    707707        self.assertEqual(('README.txt', Node.FILE, Changeset.EDIT, 
     
    713713        self.assertEqual(5, chgset.rev) 
    714714        self.assertEqual('Moved directories.', chgset.message) 
    715715        self.assertEqual('kate', chgset.author) 
    716         self.assertEqual(datetime(2005, 4, 1, 16, 25, 39, 0, utc), chgset.date) 
     716        self.assertEqual(datetime(2005, 4, 1, 16, 25, 39, 658099, utc), chgset.date) 
    717717 
    718718        changes = chgset.get_changes() 
    719719        self.assertEqual(('dir1/dir2', Node.DIRECTORY, Changeset.MOVE, 
     
    727727        self.assertEqual(6, chgset.rev) 
    728728        self.assertEqual('More things to read', chgset.message) 
    729729        self.assertEqual('john', chgset.author) 
    730         self.assertEqual(datetime(2005, 4, 1, 18, 56, 46, 0, utc), chgset.date) 
     730        self.assertEqual(datetime(2005, 4, 1, 18, 56, 46, 985846, utc), chgset.date) 
    731731 
    732732        changes = chgset.get_changes() 
    733733        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 
     
    3534from trac.search import ISearchSource, search_to_sql, shorten_result 
    3635from trac.timeline.api import ITimelineEventProvider 
    3736from trac.util import content_disposition, embedded_numbers, pathjoin 
    38 from trac.util.compat import any, set 
    39 from trac.util.datefmt import pretty_timedelta, utc 
     37from trac.util.compat import any 
     38from trac.util.datefmt import from_utimestamp, pretty_timedelta 
    4039from trac.util.text import exception_to_unicode, to_unicode, \ 
    4140                           unicode_urlencode, shorten_line, CRLF 
    4241from trac.util.translation import _, ngettext 
     
    11131112            if 'CHANGESET_VIEW' in req.perm(cset): 
    11141113                yield (req.href.changeset(rev, repos.reponame or None), 
    11151114                       '[%s]: %s' % (rev, shorten_line(log)), 
    1116                        datetime.fromtimestamp(ts, utc), author, 
    1117                        shorten_result(log, terms)) 
     1115                       from_utimestamp(ts), author, shorten_result(log, terms)) 
    11181116 
    11191117 
    11201118class 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 
     
    754754            'format_time': partial(format_time, tzinfo=tzinfo), 
    755755            'fromtimestamp': partial(datetime.datetime.fromtimestamp, 
    756756                                     tz=tzinfo), 
     757            'from_utimestamp': from_utimestamp, 
    757758 
    758759            # Wiki-formatting functions 
    759760            '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 * 
     
    2423from trac.wiki.api import WikiSystem 
    2524from trac.util import read_file 
    2625from trac.util.compat import any 
    27 from trac.util.datefmt import format_datetime, utc 
     26from trac.util.datefmt import format_datetime, from_utimestamp, \ 
     27                              to_utimestamp, utc 
    2828from trac.util.text import to_unicode, unicode_quote, unicode_unquote, \ 
    2929                           print_table, printout 
    3030from trac.util.translation import _ 
     
    147147                               "SELECT 1+COALESCE(max(version),0),%s,%s," 
    148148                               "       'trac','127.0.0.1',%s FROM wiki " 
    149149                               "WHERE name=%s", 
    150                                (title, int(time.time()), data, title)) 
     150                               (title, to_utimestamp(datetime.now(utc)), data, 
     151                                title)) 
    151152            if not old: 
    152153                WikiSystem(self.env).pages.invalidate(db) 
    153154        return result[0] 
     
    191192        cursor.execute("SELECT name, max(version), max(time) " 
    192193                       "FROM wiki GROUP BY name ORDER BY name") 
    193194        print_table([(r[0], int(r[1]), 
    194                       format_datetime(datetime.fromtimestamp(r[2], utc), 
     195                      format_datetime(from_utimestamp(r[2]), 
    195196                                      console_datetime_format)) 
    196197                     for r in cursor], 
    197198                    [_('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 
     
    2726from trac.core import * 
    2827from trac.resource import Resource, get_resource_url, get_resource_summary 
    2928from trac.util.compat import rpartition 
    30 from trac.util.datefmt import format_date, utc 
     29from trac.util.datefmt import format_date, from_utimestamp 
    3130from trac.util.html import escape 
    3231from trac.util.presentation import separated 
    3332from trac.util.text import unquote, to_unicode 
     
    225224        for name, version, ts in cursor: 
    226225            if not 'WIKI_VIEW' in formatter.perm('wiki', name, version): 
    227226                continue 
    228             time = datetime.fromtimestamp(ts, utc) 
    229             date = format_date(time) 
     227            date = format_date(from_utimestamp(ts)) 
    230228            if date != prevdate: 
    231229                prevdate = date 
    232230                entries_per_date.append((date, [])) 
  • trac/wiki/model.py

    diff --git a/trac/wiki/model.py b/trac/wiki/model.py
    a b  
    2121from trac.core import * 
    2222from trac.db.util import with_transaction 
    2323from trac.resource import Resource 
    24 from trac.util.datefmt import utc, to_timestamp 
     24from trac.util.datefmt import from_utimestamp, to_utimestamp, utc 
    2525from trac.util.translation import _ 
    2626from trac.wiki.api import WikiSystem 
    2727 
     
    7070            version, time, author, text, comment, readonly = row 
    7171            self.version = int(version) 
    7272            self.author = author 
    73             self.time = datetime.fromtimestamp(time, utc) 
     73            self.time = from_utimestamp(time) 
    7474            self.text = text 
    7575            self.comment = comment 
    7676            self.readonly = readonly and int(readonly) or 0 
     
    132132                    INSERT INTO wiki (name,version,time,author,ipnr,text, 
    133133                                      comment,readonly) 
    134134                    VALUES (%s,%s,%s,%s,%s,%s,%s,%s) 
    135                     """, (self.name, self.version + 1, to_timestamp(t), 
     135                    """, (self.name, self.version + 1, to_utimestamp(t), 
    136136                          author, remote_addr, self.text, comment, 
    137137                          self.readonly)) 
    138138                self.version += 1 
     
    166166                       "WHERE name=%s AND version<=%s " 
    167167                       "ORDER BY version DESC", (self.name, self.version)) 
    168168        for version, ts, author, comment, ipnr in cursor: 
    169             time = datetime.fromtimestamp(ts, utc) 
    170             yield version, time, author, comment, ipnr 
     169            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 
     
    5252        t = datetime(2001, 1, 1, 1, 1, 1, 0, utc) 
    5353        cursor = self.db.cursor() 
    5454        cursor.execute("INSERT INTO wiki VALUES(%s,%s,%s,%s,%s,%s,%s,%s)", 
    55                        ('TestPage', 1, to_timestamp(t), 'joe', '::1', 
     55                       ('TestPage', 1, to_utimestamp(t), 'joe', '::1', 
    5656                        'Bla bla', 'Testing', 0)) 
    5757 
    5858        page = WikiPage(self.env, 'TestPage') 
     
    9191        cursor = self.db.cursor() 
    9292        cursor.execute("SELECT version,time,author,ipnr,text,comment," 
    9393                       "readonly FROM wiki WHERE name=%s", ('TestPage',)) 
    94         self.assertEqual((1, to_timestamp(t), 'joe', '::1', 'Bla bla', 
     94        self.assertEqual((1, to_utimestamp(t), 'joe', '::1', 'Bla bla', 
    9595                          'Testing', 0), 
    9696                         cursor.fetchone()) 
    9797 
     
    103103        t = datetime(2001, 1, 1, 1, 1, 1, 0, utc) 
    104104        t2 = datetime(2002, 1, 1, 1, 1, 1, 0, utc) 
    105105        cursor.execute("INSERT INTO wiki VALUES(%s,%s,%s,%s,%s,%s,%s,%s)", 
    106                        ('TestPage', 1, to_timestamp(t), 'joe', '::1', 
     106                       ('TestPage', 1, to_utimestamp(t), 'joe', '::1', 
    107107                        'Bla bla', 'Testing', 0)) 
    108108 
    109109        page = WikiPage(self.env, 'TestPage') 
     
    119119 
    120120        cursor.execute("SELECT version,time,author,ipnr,text,comment," 
    121121                       "readonly FROM wiki WHERE name=%s", ('TestPage',)) 
    122         self.assertEqual((1, to_timestamp(t), 'joe', '::1', 'Bla bla', 
     122        self.assertEqual((1, to_utimestamp(t), 'joe', '::1', 'Bla bla', 
    123123                          'Testing', 0), 
    124124                         cursor.fetchone()) 
    125         self.assertEqual((2, to_timestamp(t2), 'kate', '192.168.0.101', 'Bla', 
     125        self.assertEqual((2, to_utimestamp(t2), 'kate', '192.168.0.101', 'Bla', 
    126126                          'Changing', 0), cursor.fetchone()) 
    127127 
    128128        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 
     
    3231from trac.search import ISearchSource, search_to_sql, shorten_result 
    3332from trac.timeline.api import ITimelineEventProvider 
    3433from trac.util import get_reporter_id 
    35 from trac.util.datefmt import to_timestamp, utc 
     34from trac.util.datefmt import from_utimestamp, to_utimestamp 
    3635from trac.util.text import shorten_line 
    3736from trac.util.translation import _ 
    3837from trac.versioncontrol.diff import get_diff_options, diff_blocks 
     
    626625            cursor = db.cursor() 
    627626            cursor.execute("SELECT time,name,comment,author,version " 
    628627                           "FROM wiki WHERE time>=%s AND time<=%s", 
    629                            (to_timestamp(start), to_timestamp(stop))) 
     628                           (to_utimestamp(start), to_utimestamp(stop))) 
    630629            for ts, name, comment, author, version in cursor: 
    631630                wiki_page = wiki_realm(id=name, version=version) 
    632631                if 'WIKI_VIEW' not in req.perm(wiki_page): 
    633632                    continue 
    634                 yield ('wiki', datetime.fromtimestamp(ts, utc), author, 
     633                yield ('wiki', from_utimestamp(ts), author, 
    635634                       (wiki_page, comment)) 
    636635 
    637636            # Attachments 
     
    682681            if 'WIKI_VIEW' in req.perm(page): 
    683682                yield (get_resource_url(self.env, page, req.href), 
    684683                       '%s: %s' % (name, shorten_line(text)), 
    685                        datetime.fromtimestamp(ts, utc), author, 
     684                       from_utimestamp(ts), author, 
    686685                       shorten_result(text, terms)) 
    687686         
    688687        # Attachments