go to post Julius Kavay · Dec 7 Could you please run the following commands in a terminal session: write $zv set exl=##class(%SYS.Python).Import("openpyxl") set wbk=exl."load_workbook"( "your path_and_filename.xlsx" ) set sht=wbk.active set cel=sht.cell(row,col) // ROW and COL should point to a date-cell write cel."data_type" write cel.value.strftime("%d.%m.%Y") Please post a screenshot here, even if you get some kind of error
go to post Julius Kavay · Dec 7 Excel store date values as decimal values (or better, as flotaing poin) as dddd.tttt where ddd is the number of days since a base date (usually 1899-12-30) and tttt is: numberOfSecondsSinceMidnight / 86400, hence the value, you get is an date-object, and you have to format it according to your needs Class DC.PyExcel Extends %RegisteredObject { ClassMethod Test(fn = "/home/kav/test/readtest.xlsx") { set exl=##class(%SYS.Python).Import("openpyxl") set wbk=exl."load_workbook"(fn) set sht=wbk.active for row=1,2,3 { for col=1:1:3 { set cel=sht.cell(row,col) set typ=cel."data_type" set val=cel.value write ?col-1*15,$case(typ, "s":val, "n":$fn(val,",",2), "d":val.strftime("%a, %d.%m.%Y"), :"") } write ! } } }
go to post Julius Kavay · Nov 19 I'm just curious, what do you get, if you type write $view(-1,$job) in the output window of Studio?See my screenshot, red=my input, yellow=Studio output
go to post Julius Kavay · Nov 18 Your lines can be shortened to if $system.Process.ClientExecutableName($j) = "..." { ... } else { ... } justmy2cents
go to post Julius Kavay · Nov 18 Port 1972 is the default port, your actual port may be different. That's why I added a comment to the answer above. Check the parameter file of your installation: for IRIS : see iris.cpf, section [Startup], DefaultPort=... for Cache: see cache.cpf, section [Startup], DefaultPort=...
go to post Julius Kavay · Nov 14 At least, there are four different ways to get that info ClassMethod StudioTest() { write "Call from Studio1: ",..InStudio1(),! write "Call from Studio2: ",..InStudio2(),! } /// Is the invocation from the Studio? ClassMethod InStudio1() { for i=$st:-1:1 if $st(i,"PLACE")["%Studio.General." ret 1 ret 0 } /// Is there a connection to Superserver? ClassMethod InStudio2() { set port=1972 // see iris.cpf, section [Startup], DefaultPort=... quit $p($v(-1,$j),"^",3)[("|TCP|"_port_"|") } Compiling routine DC.Util.1 Compilation finished successfully in 0.024s. do ##class(DC.Util).StudioTest() Call from Studio1: 1 Call from Studio2: 1 ICINDY:USER>; from PuTTY ------------------- ICINDY:USER>do ##class(DC.Util).StudioTest() Call from Studio1: 0 Call from Studio2: 0 The other two methods are: checking for the presence ofa) a dedicated variable orb) a dedicated objectbut both require a usage of undocumented functions
go to post Julius Kavay · Nov 4 Well, I'm neither part of the ObjectScript nor the Objects developer team, hence I can't answer the "why" part of your question but fact is, timing mesuremenst show a significat higher speeds for the literal versions: ClassMethod DynObject() { while $zh#1 {} set t1=$zh for i=1:1:1E6 { if ##class(%DynamicArray).%New() } set t1=$zh-t1 while $zh#1 {} set t2=$zh for i=1:1:1E6 { if ##class(%DynamicObject).%New() } set t2=$zh-t2 while $zh#1 {} set t3=$zh for i=1:1:1E6 { if [] } set t3=$zh-t3 while $zh#1 {} set t4=$zh for i=1:1:1E6 { if {} } set t4=$zh-t4 write "Times for : Class Literal Diff",! write "DynArray :", $j(t1,9,3), $j(t3,9,3), $j(t1/t3-1*100,9,2),"%",! write "DynObject :", $j(t2,9,3), $j(t4,9,3), $j(t2/t4-1*100,9,2),"%",! } The output will depend on- IRIS/Cache version in use and- on the underlying hardwareMy values are USER>d ##class(DC.Times).DynObject() Times for : Class Literal Diff DynArray : 0.665 0.401 65.90% DynObject : 0.649 0.401 61.87% Maybe someone else or the WRC has an explanation...
go to post Julius Kavay · Oct 31 JavaScript uses underscores as separators in (big)number literals. <script>alert(1_234);</script> displays 1234<script>alert(12_345_678_901_234_567_890_123n);</script> displays 12345678901234567890123 Maybe there is a quirk/problem in VS terminal...
go to post Julius Kavay · Sep 28 Oh yes, you are able to create an instance of Class Your.Page Extends %CSP.Page { Property Name As %String [ InitialExpression = "Joe" ]; } class because the inheritance goes as follows:Your.Page <-- %CSP.Page <-- %Library.Base <-- %Library.SystemBaseand the %Library.SystemBase donates you the %New() method.
go to post Julius Kavay · Sep 28 My guess is, because abstract classes (%CSP.Page is an abstract class) can't be instantiated, your subclass lacks the generator methos for property initialisation. But there is a simple solution: Class Your.Page Extends (%RegisteredObject, %CSP.Page) { Property Name As %String [ InitialExpression = "Joe" ]; } Well, the world is right again set page=##class(Your.Page).%New() write page.Name --> Joe
go to post Julius Kavay · Aug 18 Ha ha ha 😂, that's a big mistake. Those are old functions (for even older applications, maintained for backward compatibility only) in the mean time all replaced by the $list...() functions.
go to post Julius Kavay · Aug 18 Try it this way... Class DC.OldStuff Extends %Persistent [ StorageStrategy = NewStorage1 ] { Property Rec As %Integer [ Identity ]; Property Name As %String; Property City As %String; Property Phone As %String; Storage NewStorage1 { <SQLMap name="Map1"> <Data name="City"> <RetrievalCode>s {*}=$zel(^myGlo("R",{L2}),2)</RetrievalCode> </Data> <Data name="Name"> <RetrievalCode>s {*}=$zel(^myGlo("R",{L2}),1)</RetrievalCode> </Data> <Data name="Phone"> <RetrievalCode>s {*}=$zel(^myGlo("R",{L2}),3)</RetrievalCode> </Data> <Global>^myGlo</Global> <Subscript name="1"> <Expression>"R"</Expression> </Subscript> <Subscript name="2"> <Expression>{Rec}</Expression> </Subscript> <Type>data</Type> </SQLMap> <StreamLocation>^DC.OldS</StreamLocation> <Type>%CacheSQLStorage</Type> } } A short test shows, it works USER>k ^myGlo USER>s ^myGlo("R",1)=$zlp("John,Boston,11-22-33") USER>s ^myGlo("R",5)=$zlp("Laura,New York,333-444-555") USER>s ^myGlo("R",7)=$zlp("Paul,Chicago,556-666-777") USER>d $system.SQL.Shell() SQL Command Line Shell ---------------------------------------------------- The command prefix is currently set to: <<nothing>>. Enter q to quit, ? for help. USER>>select * from DC.OldStuff 3. select * from DC.OldStuff ID City Name Phone Rec 1 Boston John 11-22-33 1 5 New York Laura 333-444-555 5 7 Chicago Paul 556-666-777 7 3 Rows(s) Affected statement prepare time(s)/globals/lines/disk: 0.0003s/5/159/0ms execute time(s)/globals/lines/disk: 0.0003s/13/1136/0ms cached query class: %sqlcq.USER.cls43 --------------------------------------------------------------------------- USER>>quit or as objects USER>s obj=##class(DC.OldStuff).%OpenId(7) USER>w obj.Name,!,obj.City,!,obj.Phone Paul Chicago 556-666-777 USER>
go to post Julius Kavay · Aug 14 First step: create your own method, for example Class DC.Unix [ Abstract ] { /// Convert Posix time into Timestamp /// /// posix: posix time /// df: date format /// tf: time format /// dp: decimal places ClassMethod PosixToTimeStamp(posix, df = 3, tf = 1, dp = 0) { set posix=posix-1152921504606846976/1E6 quit $zdt(posix\86400+47117_","_(posix#86400),df,tf,dp) } } Next step, if you need more speed, instead of the parameters <df> and <tf> use constants and remove <dp>. The very last step: shorten the method name from PosixToTimeStamp() to P2TS() This way I got the (nearly) the same times as with (%Library.PosixTime).LogicalToTimeStamp, but without the need for string manipulation ICINDY:USER>k ICINDY:USER>set posix = 1154669852181849976 ICINDY:USER>while $zh#1 {} s t=$zh f i=1:1:1E6 { s x=##class(%Library.PosixTime).LogicalToTimeStamp(posix) } w $zh-t .902538 ICINDY:USER>while $zh#1 {} s t=$zh f i=1:1:1E6 { s x=##class(%Library.PosixTime).LogicalToTimeStamp(posix) } w $zh-t .90609 ICINDY:USER> ICINDY:USER>while $zh#1 {} s t=$zh f i=1:1:1E6 { s x=##class(DC.Unix).PosixToTimeStamp(posix) } w $zh-t .934834 ICINDY:USER>while $zh#1 {} s t=$zh f i=1:1:1E6 { s x=##class(DC.Unix).PosixToTimeStamp(posix) } w $zh-t .944418 ICINDY:USER> ICINDY:USER>while $zh#1 {} s t=$zh f i=1:1:1E6 { s x=##class(DC.Unix).P2TS(posix) } w $zh-t .913609 ICINDY:USER>while $zh#1 {} s t=$zh f i=1:1:1E6 { s x=##class(DC.Unix).P2TS(posix) } w $zh-t .905303 ICINDY:USER> ICINDY:USER>w $zv IRIS for UNIX (Ubuntu Server LTS for x86-64) 2021.2 (Build 649U) Thu Jan 20 2022 08:49:51 EST ICINDY:USER>w x 2025-05-27 12:06:15 ICINDY:USER>
go to post Julius Kavay · Jul 20 You have a status (or error code), OK, now take that code and make it more readable: set code=<put here your code> write $system.Status.GetErrorText(code) I think, it will be some kind of authentication issue...
go to post Julius Kavay · Jul 7 In SystemManagementPortal goto: SystemAdministration --> Configuration --> AdditionalSettings --> StartupSettings: JobServers
go to post Julius Kavay · Jul 7 I think, Enrico was more aiming for the point that “concatenation is the gateway for SQL injection.”
go to post Julius Kavay · Jul 3 An easy and simple (assuming standard storage strategy) way to get those informations (the slot numbers, where a property is stored) could be achieved with a simple classmethod Class DC.PropInfo [ Abstract ] { /// Info about properties of a class: /// - list of all properties stored in a list /// - slot number for a given property /// /// 1) add this class to your class definition /// class some.class extends (%Persistent, DC.StorageInfo) or /// class some.class extends (%SerialClass, DC.StorageInfo) /// /// 2) then use it as follows /// write ##class(some.class).PropInfo() --> list of property names /// write ##class(some.class).PropInfo("Age") --> slot number for the Age property /// /// write ##class( ClassMethod PropInfo(name = "") As %String [ CodeMode = objectgenerator ] { set sto=%compiledclass.Storages, prp=0, list="" if sto.Count()=1 { set dat=sto.GetAt(1).Data for i=1:1:dat.Count() if dat.GetAt(i).Structure="listnode" set prp=dat.GetAt(i) quit if prp { if %compiledclass.ClassType="serial" { set list="", i=1 } else { set list=$lb(""), i=2 } for i=i:1:prp.Values.Count() set list=list_$lb(prp.Values.GetAt(i).Value) } do %code.WriteLine(" if name="""" quit """_$lts(list)_"""") do %code.WriteLine(" quit $lf($lfs("""_$lts(list)_"""),name)") } if list="" write !,"*** No properties found! ***" quit $$$OK } } Two test classes Class DC.TestPerson Extends (%Persistent, DC.PropInfo) { Property Name As %String; Property Addr As DC.Address; Property Salary As %Numeric; Property Expertise As list Of %String; } Class DC.Address Extends (%SerialObject,DC.PropInfo) { Property Street As %String; Property City As %String; } Now you can do things like: write ##class(DC.TestPerson).PropInfo() --> ,Name,Addr,Salary,Expertise write ##class(DC.TestPerson).PropInfo("Salary") --> 4 // you can use the slot number for direct data access: write $list(^DC.TestPersonD(id),slotnumber) gives you the same value as write ##class(DC.TestPerson).SalaryGetStored(id) // the same game for serial classes write ##class(DC.Address).PropInfo() --> Street,City write ##class(DC.Address).PropInfo("City") --> 2 // in case you have an instance set pers=##class(DC.TestPerson).%OpenId(id) write pers.PropInfo() --> ,Name,Addr,Salary,Expertise write pers.Addr.PropInfo() --> Street,City // etc.
go to post Julius Kavay · Jun 30 Another reason for the <CLASS or ROUTINE DOES NOT EXISTS> message is that you're in the wrong namespace. Your installation has four namespaces by default: %SYS, DOCBOOK, SAMPLES, and USER. Another possibility could be misleading YouTube videos that use classes from newer Cache or IRIS versions without notice.