Fix display of dates on non english windows

This commit is contained in:
Kovid Goyal 2008-08-30 21:37:37 -07:00
parent 5c399a268e
commit 5e494d0f80
14 changed files with 188 additions and 33 deletions

View File

@ -22,6 +22,9 @@ LIBZ = '/lib/libz.so.1'
LIBBZ2 = '/lib/libbz2.so.1' LIBBZ2 = '/lib/libbz2.so.1'
LIBUSB = '/usr/lib/libusb.so' LIBUSB = '/usr/lib/libusb.so'
LIBPOPPLER = '/usr/lib/libpoppler.so.3' LIBPOPPLER = '/usr/lib/libpoppler.so.3'
LIBXML2 = '/usr/lib/libxml2.so.2'
LIBXSLT = '/usr/lib/libxslt.so.1'
LIBEXSLT = '/usr/lib/libexslt.so.0'
CALIBRESRC = os.path.join(CALIBREPREFIX, 'src') CALIBRESRC = os.path.join(CALIBREPREFIX, 'src')
@ -121,7 +124,7 @@ binaries += [('pdftohtml', PDFTOHTML, 'BINARY'),
print 'Adding external libraries...' print 'Adding external libraries...'
binaries += [ (os.path.basename(x), x, 'BINARY') for x in (SQLITE, DBUS, binaries += [ (os.path.basename(x), x, 'BINARY') for x in (SQLITE, DBUS,
LIBMNG, LIBZ, LIBBZ2, LIBUSB, LIBPOPPLER)] LIBMNG, LIBZ, LIBBZ2, LIBUSB, LIBPOPPLER, LIBXML2, LIBXSLT, LIBEXSLT)]
qt = [] qt = []

View File

@ -320,11 +320,10 @@ class LoggingInterface:
def strftime(fmt, t=time.localtime()): def strftime(fmt, t=time.localtime()):
''' ''' A version of strtime that returns unicode strings. '''
A version of strtime that returns unicode strings. if iswindows:
''' return plugins['winutil'].strftime(unicode(fmt, preferred_encoding), t)
result = time.strftime(fmt, t) return time.strftime(fmt, t).decode(preferred_encoding, 'replace')
return unicode(result, preferred_encoding, 'replace')
def entity_to_unicode(match, exceptions=[], encoding='cp1252'): def entity_to_unicode(match, exceptions=[], encoding='cp1252'):
''' '''

View File

@ -2,7 +2,7 @@ __license__ = 'GPL v3'
__copyright__ = '2008, Kovid Goyal kovid@kovidgoyal.net' __copyright__ = '2008, Kovid Goyal kovid@kovidgoyal.net'
__docformat__ = 'restructuredtext en' __docformat__ = 'restructuredtext en'
__appname__ = 'calibre' __appname__ = 'calibre'
__version__ = '0.4.84b1' __version__ = '0.4.84b2'
__author__ = "Kovid Goyal <kovid@kovidgoyal.net>" __author__ = "Kovid Goyal <kovid@kovidgoyal.net>"
''' '''
Various run time constants. Various run time constants.
@ -27,4 +27,4 @@ except:
win32event = __import__('win32event') if iswindows else None win32event = __import__('win32event') if iswindows else None
winerror = __import__('winerror') if iswindows else None winerror = __import__('winerror') if iswindows else None
win32api = __import__('win32api') if iswindows else None win32api = __import__('win32api') if iswindows else None
fcntl = None if iswindows else __import__('fcntl') fcntl = None if iswindows else __import__('fcntl')

View File

@ -9,11 +9,9 @@ from calibre.ebooks.lrf.html.convert_from import process_file
from calibre.web.feeds.main import option_parser as feeds_option_parser from calibre.web.feeds.main import option_parser as feeds_option_parser
from calibre.web.feeds.main import run_recipe from calibre.web.feeds.main import run_recipe
from calibre.ptempfile import PersistentTemporaryDirectory from calibre.ptempfile import PersistentTemporaryDirectory
from calibre import sanitize_file_name from calibre import sanitize_file_name, strftime
import sys, os, time import sys, os
import parser
def option_parser(): def option_parser():
parser = feeds_option_parser() parser = feeds_option_parser()
@ -51,7 +49,7 @@ def main(args=sys.argv, notification=None, handler=None):
if not opts.output: if not opts.output:
ext = '.lrs' if opts.lrs else '.lrf' ext = '.lrs' if opts.lrs else '.lrf'
fname = recipe.title + time.strftime(recipe.timefmt)+ext fname = recipe.title + strftime(recipe.timefmt)+ext
opts.output = os.path.join(os.getcwd(), sanitize_file_name(fname)) opts.output = os.path.join(os.getcwd(), sanitize_file_name(fname))
print 'Generating LRF...' print 'Generating LRF...'
process_file(htmlfile, opts) process_file(htmlfile, opts)

View File

@ -2,10 +2,10 @@ __license__ = 'GPL v3'
__copyright__ = '2008, Kovid Goyal <kovid at kovidgoyal.net>' __copyright__ = '2008, Kovid Goyal <kovid at kovidgoyal.net>'
'''Convert websites into LRF files.''' '''Convert websites into LRF files.'''
import sys, time, tempfile, shutil, os, logging, imp, inspect, re import sys, tempfile, shutil, os, logging, imp, inspect, re
from urlparse import urlsplit from urlparse import urlsplit
from calibre import __appname__, setup_cli_handlers, CommandLineError from calibre import __appname__, setup_cli_handlers, CommandLineError, strftime
from calibre.ebooks.lrf import option_parser as lrf_option_parser from calibre.ebooks.lrf import option_parser as lrf_option_parser
from calibre.ebooks.lrf.html.convert_from import process_file from calibre.ebooks.lrf.html.convert_from import process_file
@ -128,7 +128,7 @@ def process_profile(args, options, logger=None):
title = profile.title title = profile.title
if not title: if not title:
title = urlsplit(options.url).netloc title = urlsplit(options.url).netloc
options.title = title + time.strftime(profile.timefmt, time.localtime()) options.title = title + strftime(profile.timefmt)
options.match_regexps += profile.match_regexps options.match_regexps += profile.match_regexps
options.preprocess_regexps = profile.preprocess_regexps options.preprocess_regexps = profile.preprocess_regexps

View File

@ -306,7 +306,7 @@ class FileDialog(QObject):
QObject.connect(self.fd, SIGNAL('accepted()'), self.save_dir) QObject.connect(self.fd, SIGNAL('accepted()'), self.save_dir)
self.accepted = self.fd.exec_() == QFileDialog.Accepted self.accepted = self.fd.exec_() == QFileDialog.Accepted
else: else:
dir = dynamic.get(self.dialog_name, default=os.path.expanduser('~')) dir = dynamic.get(self.dialog_name, os.path.expanduser('~'))
self.selected_files = [] self.selected_files = []
if mode == QFileDialog.AnyFile: if mode == QFileDialog.AnyFile:
f = qstring_to_unicode( f = qstring_to_unicode(

View File

@ -13,7 +13,7 @@ from PyQt4.QtGui import QTableView, QProgressDialog, QAbstractItemView, QColor,
from PyQt4.QtCore import QAbstractTableModel, QVariant, Qt, QString, \ from PyQt4.QtCore import QAbstractTableModel, QVariant, Qt, QString, \
QCoreApplication, SIGNAL, QObject, QSize, QModelIndex QCoreApplication, SIGNAL, QObject, QSize, QModelIndex
from calibre import preferred_encoding from calibre import strftime
from calibre.ptempfile import PersistentTemporaryFile from calibre.ptempfile import PersistentTemporaryFile
from calibre.library.database import LibraryDatabase, text_to_tokens from calibre.library.database import LibraryDatabase, text_to_tokens
from calibre.gui2 import NONE, TableView, qstring_to_unicode, config from calibre.gui2 import NONE, TableView, qstring_to_unicode, config
@ -370,7 +370,7 @@ class BooksModel(QAbstractTableModel):
dt = self.db.timestamp(row) dt = self.db.timestamp(row)
if dt: if dt:
dt = dt - timedelta(seconds=time.timezone) + timedelta(hours=time.daylight) dt = dt - timedelta(seconds=time.timezone) + timedelta(hours=time.daylight)
return QVariant(dt.strftime(BooksView.TIME_FMT).decode(preferred_encoding, 'replace')) return QVariant(strftime(BooksView.TIME_FMT, dt.timetuple()))
elif col == 4: elif col == 4:
r = self.db.rating(row) r = self.db.rating(row)
r = r/2 if r else 0 r = r/2 if r else 0
@ -690,7 +690,7 @@ class DeviceBooksModel(BooksModel):
dt = item.datetime dt = item.datetime
dt = datetime(*dt[0:6]) dt = datetime(*dt[0:6])
dt = dt - timedelta(seconds=time.timezone) + timedelta(hours=time.daylight) dt = dt - timedelta(seconds=time.timezone) + timedelta(hours=time.daylight)
data[_('Timestamp')] = dt.strftime('%a %b %d %H:%M:%S %Y') data[_('Timestamp')] = strftime('%a %b %d %H:%M:%S %Y', dt.timetuple())
data[_('Tags')] = ', '.join(item.tags) data[_('Tags')] = ', '.join(item.tags)
self.emit(SIGNAL('new_bookdisplay_data(PyQt_PyObject)'), data) self.emit(SIGNAL('new_bookdisplay_data(PyQt_PyObject)'), data)
@ -731,7 +731,7 @@ class DeviceBooksModel(BooksModel):
dt = self.db[self.map[row]].datetime dt = self.db[self.map[row]].datetime
dt = datetime(*dt[0:6]) dt = datetime(*dt[0:6])
dt = dt - timedelta(seconds=time.timezone) + timedelta(hours=time.daylight) dt = dt - timedelta(seconds=time.timezone) + timedelta(hours=time.daylight)
return QVariant(dt.strftime(BooksView.TIME_FMT)) return QVariant(strftime(BooksView.TIME_FMT, dt.timetuple()))
elif col == 4: elif col == 4:
tags = self.db[self.map[row]].tags tags = self.db[self.map[row]].tags
if tags: if tags:

View File

@ -2,7 +2,8 @@
# Invoke with nmake /f Makefile.winutil # Invoke with nmake /f Makefile.winutil
test : winutil.pyd test : winutil.pyd
python.exe -c "import winutil; winutil.set_debug(True); print winutil.get_usb_devices(); print winutil.get_mounted_volumes_for_usb_device(0x054c, 0x031e)" python.exe -c "import winutil; winutil.set_debug(True); print repr(winutil.strftime(u'%b %a %A')); "
#python.exe -c "import winutil; winutil.set_debug(True); print winutil.get_usb_devices(); print winutil.get_mounted_volumes_for_usb_device(0x054c, 0x031e)"
winutil.pyd : winutil.obj winutil.pyd : winutil.obj
link.exe /DLL /nologo /INCREMENTAL:NO /LIBPATH:c:\Python25\libs \ link.exe /DLL /nologo /INCREMENTAL:NO /LIBPATH:c:\Python25\libs \

View File

@ -57,12 +57,19 @@ wherever possible in this module.
#define UNICODE #define UNICODE
#include <Windows.h> #include <Windows.h>
#include <Python.h> #include <Python.h>
#include <structseq.h>
#include <timefuncs.h>
#include <shlobj.h> #include <shlobj.h>
#include <stdio.h> #include <stdio.h>
#include <setupapi.h> #include <setupapi.h>
#include <devguid.h> #include <devguid.h>
#include <cfgmgr32.h> #include <cfgmgr32.h>
#include <stdarg.h> #include <stdarg.h>
#include <time.h>
#define PyStructSequence_GET_ITEM(op, i) \
(((PyStructSequence *)(op))->ob_item[i])
#define BUFSIZE 512 #define BUFSIZE 512
#define MAX_DRIVES 26 #define MAX_DRIVES 26
@ -515,6 +522,143 @@ winutil_is_usb_device_connected(PyObject *self, PyObject *args) {
return ans; return ans;
} }
static int
gettmarg(PyObject *args, struct tm *p)
{
int y;
memset((void *) p, '\0', sizeof(struct tm));
if (!PyArg_Parse(args, "(iiiiiiiii)",
&y,
&p->tm_mon,
&p->tm_mday,
&p->tm_hour,
&p->tm_min,
&p->tm_sec,
&p->tm_wday,
&p->tm_yday,
&p->tm_isdst))
return 0;
if (y < 1900) {
if (69 <= y && y <= 99)
y += 1900;
else if (0 <= y && y <= 68)
y += 2000;
else {
PyErr_SetString(PyExc_ValueError,
"year out of range");
return 0;
}
}
p->tm_year = y - 1900;
p->tm_mon--;
p->tm_wday = (p->tm_wday + 1) % 7;
p->tm_yday--;
return 1;
}
static PyObject *
winutil_strftime(PyObject *self, PyObject *args)
{
PyObject *tup = NULL;
struct tm buf;
PyObject *format;
const wchar_t *fmt;
size_t fmtlen, buflen;
wchar_t *outbuf = 0;
size_t i;
memset((void *) &buf, '\0', sizeof(buf));
if (!PyArg_ParseTuple(args, "U|O:strftime", &format, &tup))
return NULL;
if (tup == NULL) {
time_t tt = time(NULL);
buf = *localtime(&tt);
} else if (!gettmarg(tup, &buf))
return NULL;
if (buf.tm_mon == -1)
buf.tm_mon = 0;
else if (buf.tm_mon < 0 || buf.tm_mon > 11) {
PyErr_SetString(PyExc_ValueError, "month out of range");
return NULL;
}
if (buf.tm_mday == 0)
buf.tm_mday = 1;
else if (buf.tm_mday < 0 || buf.tm_mday > 31) {
PyErr_SetString(PyExc_ValueError, "day of month out of range");
return NULL;
}
if (buf.tm_hour < 0 || buf.tm_hour > 23) {
PyErr_SetString(PyExc_ValueError, "hour out of range");
return NULL;
}
if (buf.tm_min < 0 || buf.tm_min > 59) {
PyErr_SetString(PyExc_ValueError, "minute out of range");
return NULL;
}
if (buf.tm_sec < 0 || buf.tm_sec > 61) {
PyErr_SetString(PyExc_ValueError, "seconds out of range");
return NULL;
}
/* tm_wday does not need checking of its upper-bound since taking
``% 7`` in gettmarg() automatically restricts the range. */
if (buf.tm_wday < 0) {
PyErr_SetString(PyExc_ValueError, "day of week out of range");
return NULL;
}
if (buf.tm_yday == -1)
buf.tm_yday = 0;
else if (buf.tm_yday < 0 || buf.tm_yday > 365) {
PyErr_SetString(PyExc_ValueError, "day of year out of range");
return NULL;
}
if (buf.tm_isdst < -1 || buf.tm_isdst > 1) {
PyErr_SetString(PyExc_ValueError,
"daylight savings flag out of range");
return NULL;
}
/* Convert the unicode string to a wchar one */
fmtlen = PyUnicode_GET_SIZE(format);
fmt = (wchar_t *)PyMem_Malloc((fmtlen+1)*sizeof(wchar_t));
if (fmt == NULL) return PyErr_NoMemory();
i = PyUnicode_AsWideChar((PyUnicodeObject *)format, fmt, fmtlen);
if (i < fmtlen) {
PyErr_SetString(PyExc_RuntimeError, "Failed to convert format string");
PyMem_Free(fmt);
return NULL;
}
for (i = 1024; ; i += i) {
outbuf = (wchar_t *)PyMem_Malloc(i*sizeof(wchar_t));
if (outbuf == NULL) {
return PyErr_NoMemory();
}
buflen = wcsftime(outbuf, i, fmt, &buf);
if (buflen > 0 || i >= 256 * fmtlen) {
/* If the buffer is 256 times as long as the format,
it's probably not failing for lack of room!
More likely, the format yields an empty result,
e.g. an empty format, or %Z when the timezone
is unknown. */
PyObject *ret;
ret = PyUnicode_FromWideChar(outbuf, buflen);
PyMem_Free(outbuf); PyMem_Free(fmt);
return ret;
}
PyMem_Free(outbuf); PyMem_Free(fmt);
#if defined _MSC_VER && _MSC_VER >= 1400 && defined(__STDC_SECURE_LIB__)
/* VisualStudio .NET 2005 does this properly */
if (buflen == 0 && errno == EINVAL) {
PyErr_SetString(PyExc_ValueError, "Invalid format string");
return NULL;
}
#endif
}
}
static PyMethodDef WinutilMethods[] = { static PyMethodDef WinutilMethods[] = {
{"special_folder_path", winutil_folder_path, METH_VARARGS, {"special_folder_path", winutil_folder_path, METH_VARARGS,
@ -553,6 +697,15 @@ static PyMethodDef WinutilMethods[] = {
"set_debug(bool)\n\nSet debugging mode." "set_debug(bool)\n\nSet debugging mode."
}, },
{"strftime", winutil_strftime, METH_VARARGS,
"strftime(format[, tuple]) -> string\n\
\n\
Convert a time tuple to a string according to a format specification.\n\
See the library reference manual for formatting codes. When the time tuple\n\
is not present, current time as returned by localtime() is used. format must\n\
be a unicode string. Returns unicode strings."
},
{NULL, NULL, 0, NULL} {NULL, NULL, 0, NULL}
}; };

View File

@ -4,6 +4,7 @@ __copyright__ = '2008, Kovid Goyal kovid@kovidgoyal.net'
__docformat__ = 'restructuredtext en' __docformat__ = 'restructuredtext en'
import re, time import re, time
from calibre import strftime
from calibre.web.feeds.news import BasicNewsRecipe from calibre.web.feeds.news import BasicNewsRecipe
from calibre.ebooks.BeautifulSoup import NavigableString from calibre.ebooks.BeautifulSoup import NavigableString
@ -65,7 +66,7 @@ class NewYorker(BasicNewsRecipe):
'title': title, 'title': title,
'desc': desc, 'content':'', 'desc': desc, 'content':'',
'url': href, 'url': href,
'date': time.strftime('%a, %d %b', time.localtime()), 'date': strftime('%a, %d %b'),
} }
articles.append(art) articles.append(art)

View File

@ -3,6 +3,7 @@
__license__ = 'GPL v3' __license__ = 'GPL v3'
__copyright__ = '2008, Kovid Goyal <kovid at kovidgoyal.net>' __copyright__ = '2008, Kovid Goyal <kovid at kovidgoyal.net>'
import re, string, time import re, string, time
from calibre import strftime
from calibre.web.feeds.news import BasicNewsRecipe from calibre.web.feeds.news import BasicNewsRecipe
from calibre.ebooks.BeautifulSoup import BeautifulSoup from calibre.ebooks.BeautifulSoup import BeautifulSoup
@ -68,7 +69,7 @@ class Newsweek(BasicNewsRecipe):
small = img['src'] small = img['src']
match = re.search(r'(\d+)_', small.rpartition('/')[-1]) match = re.search(r'(\d+)_', small.rpartition('/')[-1])
if match is not None: if match is not None:
self.timefmt = time.strftime(' [%d %b, %Y]', time.strptime(match.group(1), '%y%m%d')) self.timefmt = strftime(' [%d %b, %Y]', time.strptime(match.group(1), '%y%m%d'))
self.cover_url = small.replace('coversmall', 'coverlarge') self.cover_url = small.replace('coversmall', 'coverlarge')
sections = self.get_sections(soup) sections = self.get_sections(soup)
@ -84,7 +85,7 @@ class Newsweek(BasicNewsRecipe):
'title' : title, 'title' : title,
'url' : a['href'], 'url' : a['href'],
'description':'', 'content':'', 'description':'', 'content':'',
'date': time.strftime('%a, %d %b', time.localtime()) 'date': strftime('%a, %d %b')
} }
if art['title'] and art['url']: if art['title'] and art['url']:
sections[0][1].append(art) sections[0][1].append(art)

View File

@ -5,7 +5,8 @@ __copyright__ = '2008, Kovid Goyal <kovid at kovidgoyal.net>'
''' '''
nytimes.com nytimes.com
''' '''
import time, string import string
from calibre import strftime
from calibre.web.feeds.recipes import BasicNewsRecipe from calibre.web.feeds.recipes import BasicNewsRecipe
class NYTimes(BasicNewsRecipe): class NYTimes(BasicNewsRecipe):
@ -59,7 +60,7 @@ class NYTimes(BasicNewsRecipe):
url = self.print_version(a['href']) url = self.print_version(a['href'])
title = self.tag_to_string(a, use_alt=True).strip() title = self.tag_to_string(a, use_alt=True).strip()
description = '' description = ''
pubdate = time.strftime('%a, %d %b', time.localtime()) pubdate = strftime('%a, %d %b')
summary = div.find(True, attrs={'class':'summary'}) summary = div.find(True, attrs={'class':'summary'})
if summary: if summary:
description = self.tag_to_string(summary, use_alt=False) description = self.tag_to_string(summary, use_alt=False)

View File

@ -6,7 +6,7 @@ __docformat__ = 'restructuredtext en'
''' '''
smh.com.au smh.com.au
''' '''
import time from calibre import strftime
from calibre.web.feeds.news import BasicNewsRecipe from calibre.web.feeds.news import BasicNewsRecipe
from calibre.ebooks.BeautifulSoup import BeautifulSoup from calibre.ebooks.BeautifulSoup import BeautifulSoup
@ -44,7 +44,7 @@ class SMH(BasicNewsRecipe):
articles.append({ articles.append({
'title': title, 'title': title,
'url' : url, 'url' : url,
'date' : time.strftime('%a, %d %b'), 'date' : strftime('%a, %d %b'),
'description' : '', 'description' : '',
'content' : '', 'content' : '',
}) })

View File

@ -2,9 +2,8 @@
__license__ = 'GPL v3' __license__ = 'GPL v3'
__copyright__ = '2008, Kovid Goyal <kovid at kovidgoyal.net>' __copyright__ = '2008, Kovid Goyal <kovid at kovidgoyal.net>'
import datetime
from calibre.utils.genshi.template import MarkupTemplate from calibre.utils.genshi.template import MarkupTemplate
from calibre import preferred_encoding from calibre import preferred_encoding, strftime
class Template(MarkupTemplate): class Template(MarkupTemplate):
@ -126,8 +125,7 @@ class IndexTemplate(Template):
def generate(self, title, datefmt, feeds): def generate(self, title, datefmt, feeds):
if isinstance(datefmt, unicode): if isinstance(datefmt, unicode):
datefmt = datefmt.encode(preferred_encoding) datefmt = datefmt.encode(preferred_encoding)
date = datetime.datetime.now().strftime(datefmt) date = strftime(datefmt)
date = date.decode(preferred_encoding, 'replace')
return Template.generate(self, title=title, date=date, feeds=feeds) return Template.generate(self, title=title, date=date, feeds=feeds)