Not having any luck using the standard ssf.js as ssf.py with dates
The ssf.js module (https://raw.githubusercontent.com/SheetJS/ssf/master/ssf.js) formats objects using the Excel number format. Here is the usage:
SSF.format(fmt, val, opts) formats val using the format fmt.
I converted it to python as follows (to avoid the unicode error):
>>> js = open('ssf.js', 'r', encoding="utf-8").read()
>>> py = js2py.translate_js(js)
>>> open('ssf.py', 'w', encoding="utf-8").write(py)
142637
First of all, I get this warning with no indication of where it's coming from:
>>> import ssf
C:\Users\Joe Cool\AppData\Local\Programs\Python\Python37-32\lib\site-packages\js2py\const
ructors\time_helpers.py:44: Warning: Invalid datetime date, assumed DST time, may be inacc
urate...
Warning)
Now, I need to figure out how to use this module from python. Help is no use:
>>> help(ssf)
Help on module ssf:
NAME
ssf
DATA
JS_BUILTINS = {'Array': 'function Array() { [python code] }', 'ArrayBu...
PyJs_make_ssf_0_ = 'function make_ssf(SSF) { [python code] }'
var = [Object Global]
FILE
d:\python\xls2xlsx\translated\ssf.py
Not sure if this is the right way, but I did get this to sort-of work:
>>> import ssf
>>> SSF = ssf.var['SSF']
>>> format = SSF['format']
>>> format('#', 1)
'1'
Now a little more complicated:
>>> format('# ?/?', 1.5)
'1 1/2'
So far so good. Now let's try a date:
>>> from datetime import date
>>> format('mmm d, yyyy', date(2020, 1, 3))
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "C:\Users\Joe Cool\AppData\Local\Programs\Python\Python37-32\lib\site-packages\js2
py\base.py", line 949, in __call__
return self.call(self.GlobalObject, args)
File "C:\Users\Joe Cool\AppData\Local\Programs\Python\Python37-32\lib\site-packages\js2
py\base.py", line 1464, in call
return Js(self.code(*args))
File "D:\python\xls2xlsx\translated\ssf.py", line 1419, in PyJsHoisted_format_
return var.get('eval_fmt')(var.get('f').get('1'), var.get('v'), var.get('o'), var.get(
'f').get('0'))
File "C:\Users\Joe Cool\AppData\Local\Programs\Python\Python37-32\lib\site-packages\js2
py\base.py", line 949, in __call__
return self.call(self.GlobalObject, args)
File "C:\Users\Joe Cool\AppData\Local\Programs\Python\Python37-32\lib\site-packages\js2
py\base.py", line 1464, in call
return Js(self.code(*args))
File "D:\python\xls2xlsx\translated\ssf.py", line 1279, in PyJsHoisted_eval_fmt_
var.put('retval', var.get('out').get(var.get('i')).get('v'), '+')
File "C:\Users\Joe Cool\AppData\Local\Programs\Python\Python37-32\lib\site-packages\js2
py\base.py", line 1127, in put
val = getattr(self.own[lval], OP_METHODS[op])(val)
File "C:\Users\Joe Cool\AppData\Local\Programs\Python\Python37-32\lib\site-packages\js2
py\base.py", line 776, in __add__
b = other.to_primitive()
File "C:\Users\Joe Cool\AppData\Local\Programs\Python\Python37-32\lib\site-packages\js2
py\base.py", line 548, in to_primitive
return self.default_value(hint)
File "C:\Users\Joe Cool\AppData\Local\Programs\Python\Python37-32\lib\site-packages\js2
py\base.py", line 456, in default_value
'Cannot convert object to primitive value')
js2py.internals.simplex.JsException: TypeError: Cannot convert object to primitive value
No luck there, let's make the date a string instead:
>>> format('mmm d, yyyy', '1/3/2020')
'1/3/2020'
Not quite as expected. Let's pass in the Excel integer corresponding to a date:
>>> format('mmm d, yyyy', 47712)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "C:\Users\Joe Cool\AppData\Local\Programs\Python\Python37-32\lib\site-packages\js2
py\base.py", line 949, in __call__
return self.call(self.GlobalObject, args)
File "C:\Users\Joe Cool\AppData\Local\Programs\Python\Python37-32\lib\site-packages\js2
py\base.py", line 1464, in call
return Js(self.code(*args))
File "D:\python\xls2xlsx\translated\ssf.py", line 1419, in PyJsHoisted_format_
return var.get('eval_fmt')(var.get('f').get('1'), var.get('v'), var.get('o'), var.get(
'f').get('0'))
File "C:\Users\Joe Cool\AppData\Local\Programs\Python\Python37-32\lib\site-packages\js2
py\base.py", line 949, in __call__
return self.call(self.GlobalObject, args)
File "C:\Users\Joe Cool\AppData\Local\Programs\Python\Python37-32\lib\site-packages\js2
py\base.py", line 1464, in call
return Js(self.code(*args))
File "D:\python\xls2xlsx\translated\ssf.py", line 834, in PyJsHoisted_eval_fmt_
var.put('dt', var.get('parse_date_code')(var.get('v'), var.get('opts')))
File "C:\Users\Joe Cool\AppData\Local\Programs\Python\Python37-32\lib\site-packages\js2
py\base.py", line 949, in __call__
return self.call(self.GlobalObject, args)
File "C:\Users\Joe Cool\AppData\Local\Programs\Python\Python37-32\lib\site-packages\js2
py\base.py", line 1464, in call
return Js(self.code(*args))
File "D:\python\xls2xlsx\translated\ssf.py", line 198, in PyJsHoisted_parse_date_code_
var.get('d').callprop('setDate', ((var.get('d').callprop('getDate')+var.get('date'))-J
s(1.0)))
File "C:\Users\Joe Cool\AppData\Local\Programs\Python\Python37-32\lib\site-packages\js2
py\base.py", line 995, in callprop
cand.typeof(), repr(prop), repr(self.Class)))
js2py.internals.simplex.JsException: TypeError: 'undefined' is not a function (tried calli
ng property 'setDate' of 'Date')
Ok, here is where I gave up!
Seems your last attempt found the problem: Date.prototype.setDate is not defined and is used in line 166 of ssf.js I'll have to look at the spec to see what should be done about it.
I made these usage examples while testing:
import js2py
js2py.translate_file('ssf.js', 'ssf.py')
from ssf import ssf
print ssf.SSF.format("General",js2py.eval_js("new Date(2020, 1, 3)"))
import js2py
js = open('ssf.js', 'r').read().decode('utf8')
context = js2py.EvalJs()
context.execute(js)
context.execute('''console.log(SSF.format("General", new Date(2017, 1, 19)))''')
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/setDate
I made this hacky implementation for now:
def setDate(date):
check_date(this)
t = UTCToLocal(this.value)
dt = date.to_number()
time = MakeTime(Number(HourFromTime(t)), Number(MinFromTime(t)), Number(SecFromTime(t)), Number(msFromTime(t)))
newDate = MakeDate(MakeDay(Number(YearFromTime(t)), Number(MonthFromTime(t)), dt), time)
u = TimeClip(LocalToUTC(newDate))
this.value = u
return u
It goes in js2py/constructors/jsdate.py and js2py/internals/constructors/jsdate.py just above the comment "# todo Complete all setters!". ssf then works great, but the fields returned can be off by one. Still need to find this bug.
Thanks!!
Sounds like this should be added to your test suite with a handful of test cases!
BTW, is there any way to generate a self-contained output file, eg not dependent on js2py?
I’m trying to generate a python version of this library.
I think it already has tests, it's just that it and a few other datetime setter functions are currently unimplemented.
No way to get around needing a js interpreter without actually porting the code, though.
Ok but how about the “off by 1” issue you mentioned?
It'll take a bit for me to find the issue as I need to debug the library to find exactly what triggers it. I'll reply back as soon as I have the solution.
js2py/internals/constructors/time_helpers.py, line 45, change it the return value from 1 to 0
This just disables DST in js2py. Surely there is still a bug here, but this seems to correct the issue for now. Results are the same as in my browser.
Thanks!
Yeah time zones are like the worst things to deal with in the land of programming. Worse than even file encodings! :-)
Thanks!
-Joe Sent from my AT&T iPad
On Sep 14, 2020, at 8:30 PM, worstperson [email protected] wrote:
 js2py/internals/constructors/time_helpers.py, line 45, change it the return value from 1 to 0
This just disables DST in js2py. Surely there is still a bug here, but this seems to correct the issue for now. Results are the same as in my browser.
— You are receiving this because you authored the thread. Reply to this email directly, view it on GitHub, or unsubscribe.