Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Implement pytz timezone conversation and separate command- and data-p…
…rocessing classes
- Loading branch information
1 parent
c879a70
commit 822f4bf
Showing
2 changed files
with
132 additions
and
69 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,70 +1,127 @@ | ||
import sublime | ||
import sublime_plugin | ||
from datetime import datetime, timedelta, tzinfo | ||
from functools import partial | ||
import pytz | ||
from pytz.exceptions import * | ||
|
||
|
||
class LocalDatetime(object): | ||
class LocalTimezone(tzinfo): | ||
""" | ||
Wrapper class that uses the local timezone for formatting a datetime. | ||
Helper class which extends datetime.tzinfo and implements the 'local timezone' | ||
(a.k.a. 'capturing the platform's idea of local time'). | ||
Source: http://docs.python.org/library/datetime.html#tzinfo-objects | ||
""" | ||
|
||
class LocalTimezone(tzinfo): | ||
import time | ||
""" | ||
Helper class which extends datetime.tzinfo and supports the local timezone | ||
(a.k.a. capturing the platform's idea of local time). | ||
import time | ||
|
||
Source: http://docs.python.org/library/datetime.html#tzinfo-objects""" | ||
STDOFFSET = timedelta(seconds=-time.timezone) | ||
if time.daylight: | ||
DSTOFFSET = timedelta(seconds=-time.altzone) | ||
else: | ||
DSTOFFSET = STDOFFSET | ||
|
||
STDOFFSET = timedelta(seconds=-time.timezone) | ||
if time.daylight: | ||
DSTOFFSET = timedelta(seconds=-time.altzone) | ||
else: | ||
DSTOFFSET = STDOFFSET | ||
DSTDIFF = DSTOFFSET - STDOFFSET | ||
|
||
DSTDIFF = DSTOFFSET - STDOFFSET | ||
def utcoffset(self, dt): | ||
if self._isdst(dt): | ||
return self.DSTOFFSET | ||
else: | ||
return self.STDOFFSET | ||
|
||
def utcoffset(self, dt): | ||
if self._isdst(dt): | ||
return self.DSTOFFSET | ||
else: | ||
return self.STDOFFSET | ||
def dst(self, dt): | ||
if self._isdst(dt): | ||
return self.DSTDIFF | ||
else: | ||
return timedelta(0) | ||
|
||
def dst(self, dt): | ||
if self._isdst(dt): | ||
return self.DSTDIFF | ||
else: | ||
return timedelta(0) | ||
|
||
def tzname(self, dt): | ||
# TODO: This is buggy (at least for my system) | ||
# tzname = self.time.tzname | ||
# print tzname | ||
# print("tzname: %s" % str(tzname[self._isdst(dt)])) | ||
# return self.time.tzname[self._isdst(dt)] | ||
return None | ||
|
||
def _isdst(self, dt): | ||
tt = (dt.year, dt.month, dt.day, | ||
dt.hour, dt.minute, dt.second, | ||
dt.weekday(), 0, 0) | ||
stamp = self.time.mktime(tt) | ||
tt = self.time.localtime(stamp) | ||
return tt.tm_isdst > 0 | ||
def tzname(self, dt): | ||
# TODO: This is buggy (I hate ASCII) | ||
# print self.time.tzname | ||
# print unicode(self.time.tzname[0]) | ||
# return self.time.tzname[self._isdst(dt)].decode('utf-8') | ||
return None | ||
|
||
local = LocalTimezone() | ||
def _isdst(self, dt): | ||
tt = (dt.year, dt.month, dt.day, | ||
dt.hour, dt.minute, dt.second, | ||
dt.weekday(), 0, 0) | ||
stamp = self.time.mktime(tt) | ||
tt = self.time.localtime(stamp) | ||
return tt.tm_isdst > 0 | ||
|
||
def __init__(self, dt=None): | ||
if dt is None: | ||
dt = datetime.now(tz=self.local) | ||
if not isinstance(dt, datetime): | ||
raise TypeError("Parameter is not instance of datetime.datetime") | ||
|
||
self.dt = dt.astimezone(self.local) | ||
print dt | ||
class InsertDate(object): | ||
local = LocalTimezone() | ||
default = dict( | ||
# TODO: be modifiable from settings | ||
format="%Y-%m-%d %H:%M", | ||
tz_in="Europe/Berlin" | ||
) | ||
|
||
def __init__(self, local=None, default=None): | ||
if not local is None: | ||
if isinstance(local, tzinfo): | ||
self.local = local | ||
else: | ||
raise TypeError("Parameter 'local' is not instance of datetime.tzinfo") | ||
|
||
if not default is None: | ||
try: | ||
self.default.update(default) # just raise the error if it appears | ||
except ValueError: | ||
raise ValueError("Parameter 'default' is not iterable") | ||
|
||
def parse(self, format=None, tz_in=None, tz_out=None): | ||
dt = self.date_gen(tz_in, tz_out) | ||
return self.date_format(dt, format) | ||
|
||
def date_gen(self, tz_in=None, tz_out=None): | ||
# gather tzinfo data and raise a few exceptions | ||
if tz_in is None: | ||
tz_in = self.default['tz_in'] | ||
|
||
if tz_in == "local": | ||
tz_in = self.local | ||
|
||
if isinstance(tz_in, basestring): | ||
try: | ||
tz_in = pytz.timezone(tz_in) | ||
except UnknownTimeZoneError: | ||
raise UnknownTimeZoneError("Parameter %r=%r is not a valid timezone string" % ('tz_in', tz_in)) | ||
|
||
if not isinstance(tz_in, tzinfo): | ||
raise TypeError("Parameter 'tz_in' is not instance of datetime.tzinfo") | ||
|
||
try: | ||
tz_out = pytz.timezone(tz_out) if (tz_out is not None) else tz_in | ||
except UnknownTimeZoneError: | ||
raise UnknownTimeZoneError("Parameter %r=%r is not a valid timezone string" % ('tz_out', tz_out)) | ||
|
||
# get timedata | ||
try: | ||
dt = tz_in.localize(datetime.now()) | ||
except AttributeError: | ||
dt = datetime.now(tz=tz_in) | ||
|
||
# process timedata | ||
# TODO: shift datetime here | ||
if tz_out is tz_in: | ||
return dt | ||
|
||
dt = dt.astimezone(tz_out) | ||
try: | ||
return tz_out.normalize(dt) | ||
except AttributeError: | ||
pass | ||
|
||
return dt | ||
|
||
def date_format(self, dt, format=None): | ||
if format is None: | ||
format = self.default['format'] | ||
|
||
@staticmethod | ||
def _format(dt, format): | ||
# 'iso:T' | ||
if format.startswith("iso"): | ||
sep = 'T' | ||
|
@@ -74,39 +131,42 @@ def _format(dt, format): | |
|
||
return dt.strftime(format) | ||
|
||
def format(self, format): | ||
return LocalDatetime._format(self.dt, format) | ||
|
||
def __getattr__(self, attr): | ||
return getattr(self.dt, attr) | ||
|
||
|
||
class InsertDateCommand(sublime_plugin.TextCommand): | ||
class InsertDateCommand(sublime_plugin.TextCommand, InsertDate): | ||
"""Prints Date according to given format string""" | ||
default_format = "%Y-%m-%d %H:%M" | ||
|
||
def run(self, edit, format=None, prompt=False): | ||
def run(self, edit, format=None, prompt=False, tz_in=None, tz_out=None): | ||
if prompt: | ||
self.view.window().show_input_panel( | ||
"Date format string:", | ||
format or '', | ||
str(format) if format else '', | ||
# pass this function as callback | ||
partial(self.run, edit), | ||
partial(self.run, edit, tz_in=tz_in, tz_out=tz_out), | ||
None, None | ||
) | ||
return # call already handled | ||
|
||
elif format is None: | ||
format = self.default_format | ||
if format == '' or (isinstance(format, basestring) and format.isspace()): | ||
# emtpy string or whitespaces entered in input panel | ||
return | ||
|
||
# do the actual parse action | ||
try: | ||
text = self.parse(format, tz_in, tz_out) | ||
except Exception as e: | ||
sublime.error_message("[InsertDate]\n%s: %s" % (type(e).__name__, e)) | ||
return | ||
|
||
if not format: | ||
# emtpy string entered in input panel | ||
if text == '' or text.isspace(): | ||
# don't bother replacing selections with actually nothing | ||
return | ||
|
||
text = LocalDatetime().format(format) | ||
if type(text) == str: | ||
print text | ||
text = text.decode('utf-8') | ||
This comment has been minimized.
Sorry, something went wrong.
This comment has been minimized.
Sorry, something went wrong.
FichteFoll
Author
Owner
|
||
|
||
for r in self.view.sel(): | ||
if r.empty(): | ||
self.view.insert (edit, r.begin(), text) | ||
self.view.insert (edit, r.a, text) | ||
else: | ||
self.view.replace(edit, r, text) | ||
self.view.replace(edit, r, text) |
@FichteFoll
date format:
%y-%b-%d %H:%M
or just%b
env: Windows 7 with Russian l10n, ST 2.0.1 2217
error:
If I replace
utf-8
withcp1251
then it works as it should.I'm not sure what way is best but here I've used this:
seems to work