From 45170e9fa20ec1a88bee46e0a544444c08593e26 Mon Sep 17 00:00:00 2001 From: Charles Haley <> Date: Sat, 21 Aug 2010 12:57:05 +0100 Subject: [PATCH 1/7] Sony driver: note if timezones other than local and GMT are found. --- src/calibre/devices/prs505/sony_cache.py | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/src/calibre/devices/prs505/sony_cache.py b/src/calibre/devices/prs505/sony_cache.py index 5f3e9118dc..4dee2615d6 100644 --- a/src/calibre/devices/prs505/sony_cache.py +++ b/src/calibre/devices/prs505/sony_cache.py @@ -353,20 +353,22 @@ class XMLCache(object): debug_print('Updating XML Cache:', i) root = self.record_roots[i] lpath_map = self.build_lpath_map(root) - gtz_count = ltz_count = 0 + gtz_count = ltz_count = otz_count = 0 for book in booklist: path = os.path.join(self.prefixes[i], *(book.lpath.split('/'))) record = lpath_map.get(book.lpath, None) if record is None: record = self.create_text_record(root, i, book.lpath) - (gtz_count, ltz_count) = self.update_text_record(record, book, - path, i, gtz_count, ltz_count) + (gtz_count, ltz_count, otz_count) = \ + self.update_text_record(record, book, path, i, + gtz_count, ltz_count, otz_count) # Ensure the collections in the XML database are recorded for # this book if book.device_collections is None: book.device_collections = [] book.device_collections = playlist_map.get(book.lpath, []) - debug_print('Timezone votes: %d GMT, %d LTZ'%(gtz_count, ltz_count)) + debug_print('Timezone votes: %d GMT, %d LTZ, %d OTZ'% + (gtz_count, ltz_count, otz_count)) self.update_playlists(i, root, booklist, collections_attributes) # Update the device collections because update playlist could have added # some new ones. @@ -464,7 +466,8 @@ class XMLCache(object): root.append(ans) return ans - def update_text_record(self, record, book, path, bl_index, gtz_count, ltz_count): + def update_text_record(self, record, book, path, bl_index, + gtz_count, ltz_count, otz_count): ''' Update the Sony database from the book. This is done if the timestamp in the db differs from the timestamp on the file. @@ -493,6 +496,8 @@ class XMLCache(object): gtz_count += 1 elif strftime(timestamp, zone=time.localtime) == rec_date: ltz_count += 1 + else: + otz_count += 1 else: # book is new. Set the time using the current votes if ltz_count >= gtz_count: tz = time.localtime @@ -532,7 +537,7 @@ class XMLCache(object): if 'id' not in record.attrib: num = self.max_id(record.getroottree().getroot()) record.set('id', str(num+1)) - return (gtz_count, ltz_count) + return (gtz_count, ltz_count, otz_count) # }}} # Writing the XML files {{{ From bce1ba60d2ad020ae36cc650e84ef80db860b304 Mon Sep 17 00:00:00 2001 From: Charles Haley <> Date: Mon, 23 Aug 2010 11:38:22 +0100 Subject: [PATCH 2/7] New timezone algorithm for Sony readers --- src/calibre/devices/prs505/sony_cache.py | 72 ++++++++++++------------ 1 file changed, 36 insertions(+), 36 deletions(-) diff --git a/src/calibre/devices/prs505/sony_cache.py b/src/calibre/devices/prs505/sony_cache.py index 4dee2615d6..39cff17b2c 100644 --- a/src/calibre/devices/prs505/sony_cache.py +++ b/src/calibre/devices/prs505/sony_cache.py @@ -5,7 +5,7 @@ __license__ = 'GPL v3' __copyright__ = '2010, Kovid Goyal ' __docformat__ = 'restructuredtext en' -import os, time +import os, time, datetime from base64 import b64decode from uuid import uuid4 from lxml import etree @@ -17,6 +17,7 @@ from calibre.constants import DEBUG, preferred_encoding from calibre.ebooks.chardet import xml_to_unicode from calibre.ebooks.metadata import authors_to_string, title_sort, \ authors_to_sort_string +from calibre.utils.date import fromtimestamp, utc_tz # Utility functions {{{ EMPTY_CARD_CACHE = '''\ @@ -353,22 +354,18 @@ class XMLCache(object): debug_print('Updating XML Cache:', i) root = self.record_roots[i] lpath_map = self.build_lpath_map(root) - gtz_count = ltz_count = otz_count = 0 + tz_offset = None for book in booklist: path = os.path.join(self.prefixes[i], *(book.lpath.split('/'))) record = lpath_map.get(book.lpath, None) if record is None: record = self.create_text_record(root, i, book.lpath) - (gtz_count, ltz_count, otz_count) = \ - self.update_text_record(record, book, path, i, - gtz_count, ltz_count, otz_count) + tz_offset = self.update_text_record(record, book, path, i, tz_offset) # Ensure the collections in the XML database are recorded for # this book if book.device_collections is None: book.device_collections = [] book.device_collections = playlist_map.get(book.lpath, []) - debug_print('Timezone votes: %d GMT, %d LTZ, %d OTZ'% - (gtz_count, ltz_count, otz_count)) self.update_playlists(i, root, booklist, collections_attributes) # Update the device collections because update playlist could have added # some new ones. @@ -466,46 +463,49 @@ class XMLCache(object): root.append(ans) return ans - def update_text_record(self, record, book, path, bl_index, - gtz_count, ltz_count, otz_count): + def update_text_record(self, record, book, path, bl_index, tz_offset): ''' Update the Sony database from the book. This is done if the timestamp in the db differs from the timestamp on the file. ''' - # It seems that a Sony device can sometimes know what timezone it is in, - # and apparently converts the dates to GMT when it writes them to the - # db. Unfortunately, we can't tell when it does this, so we use a - # horrible heuristic. First, set dates only for new books, trying to - # avoid upsetting the sony. Use the timezone determined through the - # voting described next. Second, voting: if a book is not new, compare - # its Sony DB date against localtime and gmtime. Count the matches. When - # we must set a date, use the one with the most matches. Use localtime - # if the case of a tie, and hope it is right. - timestamp = os.path.getmtime(path) - rec_date = record.get('date', None) - def clean(x): if isbytestring(x): x = x.decode(preferred_encoding, 'replace') x.replace(u'\0', '') return x + # It seems that a Sony device can sometimes know what timezone it is in, + # and apparently converts the dates to GMT when it writes them to the + # db. The Sony assumes that the mtime is localtime, applies its TZ + # factor, then stores the resulting date string in its DB. We compensate + # for this by reversing the computation. We first convert the string in + # the DB to datetime, forcing it to UTC (offset 0:00:00). We next + # convert the mtime to a datetime assuming that it is UTC. The + # difference between these datetimes is the timezone factor that the + # Sony used. + + timestamp = os.path.getmtime(path) if not getattr(book, '_new_book', False): # book is not new - if strftime(timestamp, zone=time.gmtime) == rec_date: - gtz_count += 1 - elif strftime(timestamp, zone=time.localtime) == rec_date: - ltz_count += 1 - else: - otz_count += 1 - else: # book is new. Set the time using the current votes - if ltz_count >= gtz_count: - tz = time.localtime - debug_print("Using localtime TZ for new book", book.lpath) - else: - tz = time.gmtime - debug_print("Using GMT TZ for new book", book.lpath) - date = strftime(timestamp, zone=tz) + rec_date = record.get('date', None) + if tz_offset is None and record.get('tz', None) == '0': + # All existing books should have the same offset, so simply use + # the first one we see. However, some (perhaps all) Sony DBs + # have an attribute called TZ, and it is not clear what this + # attribute means. Because it is set to "0" by the reader for + # books added by Calibre, to avoid confusion we will use the + # offset for the first book with that value. + tt = strptime(rec_date) + dt = datetime.datetime(tt.tm_year, tt.tm_mon, tt.tm_mday, tt.tm_hour, + tt.tm_min, tt.tm_sec, tzinfo=utc_tz) + tz_offset = dt - fromtimestamp(timestamp) + debug_print('Timezone offset:', tz_offset) + else: # book is new. Set the time using the current offset + if tz_offset is None: + # No existing books! Assume a zero offset + tz_offset = datetime.timedelta() + debug_print('Timezone offset: using default of ', tz_offset) + date = strftime(fromtimestamp(timestamp) - tz_offset) record.set('date', clean(date)) record.set('size', clean(str(os.stat(path).st_size))) @@ -537,7 +537,7 @@ class XMLCache(object): if 'id' not in record.attrib: num = self.max_id(record.getroottree().getroot()) record.set('id', str(num+1)) - return (gtz_count, ltz_count, otz_count) + return tz_offset # }}} # Writing the XML files {{{ From 4afad8585592697b83e4795d35581571ae2b5473 Mon Sep 17 00:00:00 2001 From: Charles Haley <> Date: Mon, 23 Aug 2010 11:56:16 +0100 Subject: [PATCH 3/7] Implement enhancement #6577 (Date format) created by chattympc --- resources/default_tweaks.py | 6 ++++-- src/calibre/gui2/library/delegates.py | 10 +++++----- 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/resources/default_tweaks.py b/resources/default_tweaks.py index 07aee5c6fa..e03b0680be 100644 --- a/resources/default_tweaks.py +++ b/resources/default_tweaks.py @@ -44,7 +44,7 @@ bool_custom_columns_are_tristate = 'yes' # title within authors. sort_columns_at_startup = None -# Format to be used for publication date +# Format to be used for publication date and the timestamp (date). # A string controlling how the publication date is displayed in the GUI # d the day as number without a leading zero (1 to 31) # dd the day as number with a leading zero (01 to 31) @@ -59,8 +59,10 @@ sort_columns_at_startup = None # For example, given the date of 9 Jan 2010, the following formats show # MMM yyyy ==> Jan 2010 yyyy ==> 2010 dd MMM yyyy ==> 09 Jan 2010 # MM/yyyy ==> 01/2010 d/M/yy ==> 9/1/10 yy ==> 10 -# default if not set: MMM yyyy +# publication default if not set: MMM yyyy +# timestamp default if not set: dd MMM yyyy gui_pubdate_display_format = 'MMM yyyy' +gui_timestamp_display_format = 'dd MMM yyyy' # Control title and series sorting in the library view. # If set to 'library_order', Leading articles such as The and A will be ignored. diff --git a/src/calibre/gui2/library/delegates.py b/src/calibre/gui2/library/delegates.py index 40f7a2e4e0..d98d9a240b 100644 --- a/src/calibre/gui2/library/delegates.py +++ b/src/calibre/gui2/library/delegates.py @@ -98,14 +98,14 @@ class DateDelegate(QStyledItemDelegate): # {{{ d = val.toDate() if d <= UNDEFINED_QDATE: return '' - return format_date(d.toPyDate(), 'dd MMM yyyy') + format = tweaks['gui_timestamp_display_format'] + if format is None: + format = 'dd MMM yyyy' + return format_date(d.toPyDate(), format) def createEditor(self, parent, option, index): qde = QStyledItemDelegate.createEditor(self, parent, option, index) - stdformat = unicode(qde.displayFormat()) - if 'yyyy' not in stdformat: - stdformat = stdformat.replace('yy', 'yyyy') - qde.setDisplayFormat(stdformat) + qde.setDisplayFormat('dd MMM yyyy') qde.setMinimumDate(UNDEFINED_QDATE) qde.setSpecialValueText(_('Undefined')) qde.setCalendarPopup(True) From 13a9d619694d77ec290b4eeea1111dfa38aa267d Mon Sep 17 00:00:00 2001 From: Charles Haley <> Date: Mon, 23 Aug 2010 12:20:01 +0100 Subject: [PATCH 4/7] Enhancement: add a 'remove all tags' checkbox to bulk edit --- src/calibre/gui2/dialogs/metadata_bulk.py | 5 ++++- src/calibre/gui2/dialogs/metadata_bulk.ui | 15 ++++++++++++--- 2 files changed, 16 insertions(+), 4 deletions(-) diff --git a/src/calibre/gui2/dialogs/metadata_bulk.py b/src/calibre/gui2/dialogs/metadata_bulk.py index fc0a0c5840..de483720fc 100644 --- a/src/calibre/gui2/dialogs/metadata_bulk.py +++ b/src/calibre/gui2/dialogs/metadata_bulk.py @@ -199,7 +199,10 @@ class MetadataBulkDialog(QDialog, Ui_MetadataBulkDialog): for w in getattr(self, 'custom_column_widgets', []): w.gui_val - remove = unicode(self.remove_tags.text()).strip().split(',') + if self.remove_all_tags.isChecked(): + remove = self.db.all_tags() + else: + remove = unicode(self.remove_tags.text()).strip().split(',') add = unicode(self.tags.text()).strip().split(',') au = unicode(self.authors.text()) aus = unicode(self.author_sort.text()) diff --git a/src/calibre/gui2/dialogs/metadata_bulk.ui b/src/calibre/gui2/dialogs/metadata_bulk.ui index 2cdef2b12a..4287ca5c79 100644 --- a/src/calibre/gui2/dialogs/metadata_bulk.ui +++ b/src/calibre/gui2/dialogs/metadata_bulk.ui @@ -140,7 +140,7 @@ - + true @@ -191,14 +191,23 @@ - + Comma separated list of tags to remove from the books. - + + + + Remove all + + + Check this box to remove all tags from the books. + + + &Series: From 9a9b94ef0b46039ab11e806bffffcb496141492a Mon Sep 17 00:00:00 2001 From: Charles Haley <> Date: Mon, 23 Aug 2010 12:28:16 +0100 Subject: [PATCH 5/7] Improve performance of 'remove all tags' in custom_column_widgets.py --- src/calibre/gui2/custom_column_widgets.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/calibre/gui2/custom_column_widgets.py b/src/calibre/gui2/custom_column_widgets.py index f364638f37..0e89358c53 100644 --- a/src/calibre/gui2/custom_column_widgets.py +++ b/src/calibre/gui2/custom_column_widgets.py @@ -550,9 +550,7 @@ class BulkText(BulkBase): remove_all, adding, rtext = self.gui_val remove = set() if remove_all: - for book_id in book_ids: - remove |= set(self.db.get_custom(book_id, num=self.col_id, - index_is_id=True)) + remove = set(self.db.all_custom(num=self.col_id)) else: txt = rtext if txt: From 95429a33c62dfe1068081cce170a8962b803b4f9 Mon Sep 17 00:00:00 2001 From: Charles Haley <> Date: Tue, 24 Aug 2010 11:00:20 +0100 Subject: [PATCH 6/7] Put sony driver back the way it was. Next, will put in code that will use tz variable, if it exists. --- src/calibre/devices/prs505/sony_cache.py | 67 +++++++++++------------- 1 file changed, 31 insertions(+), 36 deletions(-) diff --git a/src/calibre/devices/prs505/sony_cache.py b/src/calibre/devices/prs505/sony_cache.py index 39cff17b2c..5f3e9118dc 100644 --- a/src/calibre/devices/prs505/sony_cache.py +++ b/src/calibre/devices/prs505/sony_cache.py @@ -5,7 +5,7 @@ __license__ = 'GPL v3' __copyright__ = '2010, Kovid Goyal ' __docformat__ = 'restructuredtext en' -import os, time, datetime +import os, time from base64 import b64decode from uuid import uuid4 from lxml import etree @@ -17,7 +17,6 @@ from calibre.constants import DEBUG, preferred_encoding from calibre.ebooks.chardet import xml_to_unicode from calibre.ebooks.metadata import authors_to_string, title_sort, \ authors_to_sort_string -from calibre.utils.date import fromtimestamp, utc_tz # Utility functions {{{ EMPTY_CARD_CACHE = '''\ @@ -354,18 +353,20 @@ class XMLCache(object): debug_print('Updating XML Cache:', i) root = self.record_roots[i] lpath_map = self.build_lpath_map(root) - tz_offset = None + gtz_count = ltz_count = 0 for book in booklist: path = os.path.join(self.prefixes[i], *(book.lpath.split('/'))) record = lpath_map.get(book.lpath, None) if record is None: record = self.create_text_record(root, i, book.lpath) - tz_offset = self.update_text_record(record, book, path, i, tz_offset) + (gtz_count, ltz_count) = self.update_text_record(record, book, + path, i, gtz_count, ltz_count) # Ensure the collections in the XML database are recorded for # this book if book.device_collections is None: book.device_collections = [] book.device_collections = playlist_map.get(book.lpath, []) + debug_print('Timezone votes: %d GMT, %d LTZ'%(gtz_count, ltz_count)) self.update_playlists(i, root, booklist, collections_attributes) # Update the device collections because update playlist could have added # some new ones. @@ -463,49 +464,43 @@ class XMLCache(object): root.append(ans) return ans - def update_text_record(self, record, book, path, bl_index, tz_offset): + def update_text_record(self, record, book, path, bl_index, gtz_count, ltz_count): ''' Update the Sony database from the book. This is done if the timestamp in the db differs from the timestamp on the file. ''' + # It seems that a Sony device can sometimes know what timezone it is in, + # and apparently converts the dates to GMT when it writes them to the + # db. Unfortunately, we can't tell when it does this, so we use a + # horrible heuristic. First, set dates only for new books, trying to + # avoid upsetting the sony. Use the timezone determined through the + # voting described next. Second, voting: if a book is not new, compare + # its Sony DB date against localtime and gmtime. Count the matches. When + # we must set a date, use the one with the most matches. Use localtime + # if the case of a tie, and hope it is right. + timestamp = os.path.getmtime(path) + rec_date = record.get('date', None) + def clean(x): if isbytestring(x): x = x.decode(preferred_encoding, 'replace') x.replace(u'\0', '') return x - # It seems that a Sony device can sometimes know what timezone it is in, - # and apparently converts the dates to GMT when it writes them to the - # db. The Sony assumes that the mtime is localtime, applies its TZ - # factor, then stores the resulting date string in its DB. We compensate - # for this by reversing the computation. We first convert the string in - # the DB to datetime, forcing it to UTC (offset 0:00:00). We next - # convert the mtime to a datetime assuming that it is UTC. The - # difference between these datetimes is the timezone factor that the - # Sony used. - - timestamp = os.path.getmtime(path) if not getattr(book, '_new_book', False): # book is not new - rec_date = record.get('date', None) - if tz_offset is None and record.get('tz', None) == '0': - # All existing books should have the same offset, so simply use - # the first one we see. However, some (perhaps all) Sony DBs - # have an attribute called TZ, and it is not clear what this - # attribute means. Because it is set to "0" by the reader for - # books added by Calibre, to avoid confusion we will use the - # offset for the first book with that value. - tt = strptime(rec_date) - dt = datetime.datetime(tt.tm_year, tt.tm_mon, tt.tm_mday, tt.tm_hour, - tt.tm_min, tt.tm_sec, tzinfo=utc_tz) - tz_offset = dt - fromtimestamp(timestamp) - debug_print('Timezone offset:', tz_offset) - else: # book is new. Set the time using the current offset - if tz_offset is None: - # No existing books! Assume a zero offset - tz_offset = datetime.timedelta() - debug_print('Timezone offset: using default of ', tz_offset) - date = strftime(fromtimestamp(timestamp) - tz_offset) + if strftime(timestamp, zone=time.gmtime) == rec_date: + gtz_count += 1 + elif strftime(timestamp, zone=time.localtime) == rec_date: + ltz_count += 1 + else: # book is new. Set the time using the current votes + if ltz_count >= gtz_count: + tz = time.localtime + debug_print("Using localtime TZ for new book", book.lpath) + else: + tz = time.gmtime + debug_print("Using GMT TZ for new book", book.lpath) + date = strftime(timestamp, zone=tz) record.set('date', clean(date)) record.set('size', clean(str(os.stat(path).st_size))) @@ -537,7 +532,7 @@ class XMLCache(object): if 'id' not in record.attrib: num = self.max_id(record.getroottree().getroot()) record.set('id', str(num+1)) - return tz_offset + return (gtz_count, ltz_count) # }}} # Writing the XML files {{{ From 359abd5d8ba42a1c572d553a5907481efbc9f80d Mon Sep 17 00:00:00 2001 From: Charles Haley <> Date: Tue, 24 Aug 2010 12:39:25 +0100 Subject: [PATCH 7/7] Another attempt at fixing sony dates: combine previous voting method with use of the tz variable. --- src/calibre/devices/prs505/sony_cache.py | 56 +++++++++++++++--------- 1 file changed, 35 insertions(+), 21 deletions(-) diff --git a/src/calibre/devices/prs505/sony_cache.py b/src/calibre/devices/prs505/sony_cache.py index 5f3e9118dc..b5a8f08541 100644 --- a/src/calibre/devices/prs505/sony_cache.py +++ b/src/calibre/devices/prs505/sony_cache.py @@ -354,19 +354,22 @@ class XMLCache(object): root = self.record_roots[i] lpath_map = self.build_lpath_map(root) gtz_count = ltz_count = 0 + use_tz_var = False for book in booklist: path = os.path.join(self.prefixes[i], *(book.lpath.split('/'))) record = lpath_map.get(book.lpath, None) if record is None: record = self.create_text_record(root, i, book.lpath) - (gtz_count, ltz_count) = self.update_text_record(record, book, - path, i, gtz_count, ltz_count) + (gtz_count, ltz_count, use_tz_var) = \ + self.update_text_record(record, book, path, i, + gtz_count, ltz_count, use_tz_var) # Ensure the collections in the XML database are recorded for # this book if book.device_collections is None: book.device_collections = [] book.device_collections = playlist_map.get(book.lpath, []) - debug_print('Timezone votes: %d GMT, %d LTZ'%(gtz_count, ltz_count)) + debug_print('Timezone votes: %d GMT, %d LTZ, use_tz_var='% + (gtz_count, ltz_count, use_tz_var)) self.update_playlists(i, root, booklist, collections_attributes) # Update the device collections because update playlist could have added # some new ones. @@ -464,21 +467,27 @@ class XMLCache(object): root.append(ans) return ans - def update_text_record(self, record, book, path, bl_index, gtz_count, ltz_count): + def update_text_record(self, record, book, path, bl_index, + gtz_count, ltz_count, use_tz_var): ''' Update the Sony database from the book. This is done if the timestamp in the db differs from the timestamp on the file. ''' # It seems that a Sony device can sometimes know what timezone it is in, - # and apparently converts the dates to GMT when it writes them to the - # db. Unfortunately, we can't tell when it does this, so we use a - # horrible heuristic. First, set dates only for new books, trying to - # avoid upsetting the sony. Use the timezone determined through the - # voting described next. Second, voting: if a book is not new, compare - # its Sony DB date against localtime and gmtime. Count the matches. When - # we must set a date, use the one with the most matches. Use localtime - # if the case of a tie, and hope it is right. + # and apparently converts the dates to GMT when it writes them to its + # DB. We can detect that a device is timezone-aware because there is a + # 'tz' variable in the Sony DB, which we can set to "0" to tell the + # device to ignore its own timezone when comparing mtime to the date in + # the DB. + + # Unfortunately, if there is no tz variable in the DB, then we can't + # tell when the device applies a timezone conversion. We use a horrible + # heuristic to work around this problem. First, set dates only for new + # books, trying to avoid upsetting the sony. Second, voting: if a book + # is not new, compare its Sony DB date against localtime and gmtime. + # Count the matches. When we must set a date, use the one with the most + # matches. Use localtime if the case of a tie, and hope it is right. timestamp = os.path.getmtime(path) rec_date = record.get('date', None) @@ -489,20 +498,25 @@ class XMLCache(object): return x if not getattr(book, '_new_book', False): # book is not new - if strftime(timestamp, zone=time.gmtime) == rec_date: - gtz_count += 1 - elif strftime(timestamp, zone=time.localtime) == rec_date: - ltz_count += 1 + if record.get('tz', None) is not None: + use_tz_var = True + if strftime(timestamp, zone=time.gmtime) == rec_date: + gtz_count += 1 + elif strftime(timestamp, zone=time.localtime) == rec_date: + ltz_count += 1 else: # book is new. Set the time using the current votes - if ltz_count >= gtz_count: + if use_tz_var: tz = time.localtime - debug_print("Using localtime TZ for new book", book.lpath) + record.set('tz', '0') + debug_print("Use localtime TZ and tz='0' for new book", book.lpath) + elif ltz_count >= gtz_count: + tz = time.localtime + debug_print("Use localtime TZ for new book", book.lpath) else: tz = time.gmtime - debug_print("Using GMT TZ for new book", book.lpath) + debug_print("Use GMT TZ for new book", book.lpath) date = strftime(timestamp, zone=tz) record.set('date', clean(date)) - record.set('size', clean(str(os.stat(path).st_size))) title = book.title if book.title else _('Unknown') record.set('title', clean(title)) @@ -532,7 +546,7 @@ class XMLCache(object): if 'id' not in record.attrib: num = self.max_id(record.getroottree().getroot()) record.set('id', str(num+1)) - return (gtz_count, ltz_count) + return (gtz_count, ltz_count, use_tz_var) # }}} # Writing the XML files {{{