Documentation: The documentation is available in English README.md as well as in German README_DE.md.
- Gregorian Calender
- Date, Time and Timestamp
- Execute Operating System Commands
- JSON Utilities
The class arsblue.util.Calendar
supports problems with date and time. The following are the features that are not present in any standard InterSystems IRIS date or time implementation. Detailed information on the method parameters of the presented methods or all available methods can be found in the InterSystems IRIS class documentation.
The functions have been implemented due to European requirements, i.e. one week starts with Monday and ends with Sunday, and the holidays are the same as the configured locale. Currently, the holidays are available for Germany (Protestant and Roman Catholic feast days) and Austria (Roman Catholic feast days). However, the interface can be individually extended for each country.
The methods described below have a range of values from 31/12/1840 to 31/12/9999 based on the IRIS $HOROLOG
implementation. Below or above no values can be supplied. Resulting special cases are mentioned in the following methods.
This method can be used to check a year whether it is a leap year.
USER>write ##class(arsblue.util.Calendar).IsLeapYear(2019)
0
USER>write ##class(arsblue.util.Calendar).IsLeapYear(2020)
1
This method can be used to determine the number of days in a month. Leap years are taken into account.
USER>write ##class(arsblue.util.Calendar).GetDaysInMonth(2019,2)
28
USER>write ##class(arsblue.util.Calendar).GetDaysInMonth(2020,2)
29
This method can be used to determine the number of calendar weeks in a year.
USER>write ##class(arsblue.util.Calendar).GetWeeksInYear(2019)
52
USER>write ##class(arsblue.util.Calendar).GetWeeksInYear(2020)
53
This method can be used to determine the calendar week for a date.
USER>set var=20160101 write "week for ",var," is ",##class(arsblue.util.Calendar).GetWeekInYear(.var)," in ",var
week for 20160101 is 53 in 2015
USER>set var=20170101 write "week for ",var," is ",##class(arsblue.util.Calendar).GetWeekInYear(.var)," in ",var
week for 20170101 is 52 in 2016
USER>set var=20180101 write "week for ",var," is ",##class(arsblue.util.Calendar).GetWeekInYear(.var)," in ",var
week for 20180101 is 01 in 2018
This method can be used to determine the first day (Monday) for a calendar week.
USER>write ##class(arsblue.util.Calendar).GetFirstDayInWeek(201553)
20151228
USER>write ##class(arsblue.util.Calendar).GetFirstDayInWeek(201652)
20161226
USER>write ##class(arsblue.util.Calendar).GetFirstDayInWeek(201752)
20171225
Since the calendar week is not year-old, there is a special variant of this method, which does not deliver the first day of the calendar week at the turn of the year, but the first day of the year (otherwise, this method works the same as the standard method).
USER>write ##class(arsblue.util.Calendar).GetFirstDayInWeek(201901)
20181231
USER>write ##class(arsblue.util.Calendar).GetFirstDayInWeekInYear(201901)
20190101
Since the correct date can not be delivered due to the InterSystems IRIS $HOROLOG
implementation for calendar week 1840/53, the first valid InterSystems IRIS $HOROLOG
date (31.12.1840) will be delivered.
This method can be used to determine the last day (Sunday) for a calendar week.
USER>write ##class(arsblue.util.Calendar).GetLastDayInWeek(201553)
20160103
USER>write ##class(arsblue.util.Calendar).GetLastDayInWeek(201652)
20170101
USER>write ##class(arsblue.util.Calendar).GetLastDayInWeek(201752)
20171231
Since the correct date can not be delivered due to the InterSystems IRIS $HOROLOG
implementation for the calendar week 9999/52, the last valid InterSystems IRIS $HOROLOG
date (31.12.9999) will be delivered.
With this method the day of the week can be determined for a date (1
= Monday to 7
= Sunday).
USER>write ##class(arsblue.util.Calendar).GetDayInWeek(20190101)
2
With this method, the Easter Sunday can be determined for a year. This day is used for the calculation of most church holidays for the Evangelical or Roman Catholic Church.
USER>write ##class(arsblue.util.Calendar).GetEaster(2019)
20190421
Due to the InterSystems IRIS $HOROLOG
implementation, Easter Sunday can not be determined before 1841 or after 9999.
This method can be used to determine for a date whether it is a holiday or not. Furthermore, all holidays of a year can be determined with the same method. The example shown below uses Austria (AT) as the country setting.
USER>write ##class(arsblue.util.Calendar).GetHoliday(20190214,,,.holidays)
valentines_day
USER>zw holidays
holidays(20190101)=$lb(1,"new_years_day")
holidays(20190106)=$lb(1,"epiphany")
holidays(20190214)=$lb(0,"valentines_day")
holidays(20190304)=$lb(0,"shrove_monday")
holidays(20190305)=$lb(0,"shrove_tuesday")
holidays(20190306)=$lb(0,"ash_wednesday")
holidays(20190319)=$lb("K,ST,T,V","josef_day")
holidays(20190414)=$lb(0,"palm_sunday")
holidays(20190418)=$lb(0,"maundy_thursday")
holidays(20190419)=$lb(0,"good_friday")
holidays(20190421)=$lb(1,"easter_sunday")
holidays(20190422)=$lb(1,"easter_monday")
holidays(20190501)=$lb(1,"labor_day")
holidays(20190504)=$lb("O","florian_day")
holidays(20190530)=$lb(1,"ascension_day")
holidays(20190609)=$lb(1,"whit_sunday")
holidays(20190610)=$lb(1,"whit_monday")
holidays(20190620)=$lb(1,"feast_of_corpus_christi")
holidays(20190815)=$lb(1,"assumption_day")
holidays(20190924)=$lb("S","rupert_day")
holidays(20191010)=$lb("K","popular_vote_day")
holidays(20191026)=$lb(1,"national_holiday")
holidays(20191031)=$lb(0,"halloween")
holidays(20191101)=$lb(1,"all_saints_day")
holidays(20191111)=$lb("B","martin_day")
holidays(20191115)=$lb("N,W","leopold_day")
holidays(20191201)=$lb(0,"1st_sunday_in_advent")
holidays(20191206)=$lb(,"saint_nicholas_day")
holidays(20191208)=$lb(1,"immaculate_conception_day,2nd_sunday_in_advent")
holidays(20191215)=$lb(0,"3th_sunday_in_advent")
holidays(20191222)=$lb(0,"4th_sunday_in_advent")
holidays(20191224)=$lb(.5,"christmas_eve")
holidays(20191225)=$lb(1,"christmas_day")
holidays(20191226)=$lb(1,"boxing_day")
holidays(20191231)=$lb(.5,"new_years_eve")
The list of all holidays is given by reference only and contains per date an InterSystems IRIS $LIST
with the information whether it is a whole (1
), a half (.5
) or no (0
) legal Holiday is about or whether it is a holiday that is committed only in certain states (comma-separated list of all provincial abbreviations) and if two holidays on the same date, their identifiers are given as a comma-separated list.
Due to the InterSystems IRIS $HOROLOG
implementation no holidays can be determined before the year 1841 and after the year 9999.
If holidays are needed for a country that has not yet been implemented, this can be done simply by creating a class arsblue.util.Calendar.<Country code>
and extending the class arsblue.util.Calendar
. Only the method GetHoliday(...)
has to be overwritten.
/// Holidays for country XY
Class arsblue.util.Calendar.XY extends arsblue.util.Calendar
{
/// Create holidays for year
/// <ul>
/// <li>yyyy...the year to created holidays for.</li>
/// <li>holidays...the created holidays (by reference).</li>
/// </ul>
ClassMethod CreateHolidays(yyyy as %Integer = 0, ByRef holidays)
{
// e.g. holiday by law: 1st of January each year
Set holidays(yyyy_"0101")=$LB(1,"new_years_day")
// e.g. not a real holiday, but you do not want to forget it
Set holidays(yyyy_"0214")=$LB(0,"valentines_day")
// e.g. holiday in just a few states (a, b and c) in country XY
Set holidays(yyyy_"0301")=$LB("a,b,c","begin_of_spring")
//... more holidays to define ...
}
}
You should always calculate all possible holidays. The caching of holidays is the responsibility of the application that implements them!
The arsblue.util.DateTime
class contains the functionality that could not be accommodated directly by the InterSystems IRIS specification of data types (for example, no SQL procedures are allowed in data types, etc.).
This method allows you to freely move the date, time or timestamp to another format.
USER>write ##class(arsblue.util.DateTime).Format(20190406213405.123, "yyyyMMddHHmmss.SSS", "EEEE, dd-MM-yyyy/ww HH:mm:ss (SSS)")
Samstag, 06-04-2019/14 21:34:05 (123)
The same method can also be called as an SQL procedure.
SELECT arsblue_util.DateTime_Format(20190406213405.123, 'yyyyMMddHHmmss.SSS','EEEE, dd-MM-yyyy/ww HH:mm:ss (SSS)')
The standard InterSystems IRIS implementation already offers a number of options for executing a command in the operating system. The class arsblue.util.Exec
extends these functionalities to simplify the processing in InterSystems IRIS.
In the standard InterSystems IRIS implementation, the programmer himself has to take care of capturing the output or the error output. The output and error output can be queried directly via data streams.
USER>write $System.Status.GetErrorText(##class(arsblue.util.Exec).Call("dir",,,.out,.err))
USER>do out.OutputToDevice()
Volume in Laufwerk C: hat keine Bezeichnung.
Volumeseriennummer: F0D2-A330
Verzeichnis von c:\intersystems\iris\mgr\user
01.05.2019 14:30 <DIR> .
01.05.2019 14:30 <DIR> ..
12.04.2019 10:27 5 209 325 568 IRIS.DAT
17.04.2019 08:56 46 iris.lck
28.09.2018 16:57 <DIR> stream
2 Datei(en), 5 209 325 614 Bytes
3 Verzeichnis(se), 94 616 862 720 Bytes frei
USER>do err.OutputToDevice()
USER>write $System.Status.GetErrorText(##class(arsblue.util.Exec).Call("unknown_cmd",,,.out,.err))
FEHLER #5001: unknown_cmd returns 1
USER>do out.OutputToDevice()
USER>do err.OutputToDevice()
Der Befehl "unknown_cmd" ist entweder falsch geschrieben oder konnte nicht gefunden werden.
The output and error output can also be captured in the same data stream (example see Submit Input). The output and error output can also be output on the current device by passing the current $IO
variable for the data streams (example see Specify Directory).
In the standard InterSystems IRIS implementation, the programmer himself has to take care of the transfer of the input. The input can be transferred directly via a data stream.
USER>set in=##class(%Stream.TmpCharacter).%New()
USER>do in.WriteLine("dir"),in.WriteLine("unknown_cmd")
USER>do in.OutputToDevice()
dir
unknown_cmd
USER>write $System.Status.GetErrorText(##class(arsblue.util.Exec).Call("cmd",,in,.out,.err))
USER>do out.OutputToDevice()
Microsoft Windows [Version 10.0.17134.706]
(c) 2018 Microsoft Corporation. Alle Rechte vorbehalten.
c:\intersystems\iris\mgr\user>dir
Volume in Laufwerk C: hat keine Bezeichnung.
Volumeseriennummer: F0D2-A330
Verzeichnis von c:\intersystems\iris\mgr\user
01.05.2019 14:30 <DIR> .
01.05.2019 14:30 <DIR> ..
12.04.2019 10:27 5 209 325 568 IRIS.DAT
17.04.2019 08:56 46 iris.lck
28.09.2018 16:57 <DIR> stream
2 Datei(en), 5 209 325 614 Bytes
3 Verzeichnis(se), 94 612 426 752 Bytes frei
c:\intersystems\iris\mgr\user>unknown_cmd
c:\intersystems\iris\mgr\user>
USER>do err.OutputToDevice()
The command "unknown_cmd" is either misspelled or could not be found.
The example above now shows that the output and the error output in each case give no indication of the order in which they happened. It makes sense to expect multiple outputs and error outputs to merge the two into one data stream.
USER>set in=##class(%Stream.TmpCharacter).%New()
USER>do in.WriteLine("dir"),in.WriteLine("unknown_cmd")
USER>do in.OutputToDevice()
dir
unknown_cmd
USER>set outerr=##class(%Stream.TmpCharacter).%New()
USER>write $System.Status.GetErrorText(##class(arsblue.util.Exec).Call("cmd",,in,.outerr,.outerr))
USER>do outerr.OutputToDevice()
Microsoft Windows [Version 10.0.17134.706]
(c) 2018 Microsoft Corporation. Alle Rechte vorbehalten.
c:\intersystems\iris\mgr\user>dir
Volume in Laufwerk C: hat keine Bezeichnung.
Volumeseriennummer: F0D2-A330
Verzeichnis von c:\intersystems\iris\mgr\user
01.05.2019 14:30 <DIR> .
01.05.2019 14:30 <DIR> ..
12.04.2019 10:27 5 209 325 568 IRIS.DAT
17.04.2019 08:56 46 iris.lck
28.09.2018 16:57 <DIR> stream
2 Datei(en), 5 209 325 614 Bytes
3 Verzeichnis(se), 94 607 515 648 Bytes frei
c:\intersystems\iris\mgr\user>unknown_cmd
The command "unknown_cmd" is either misspelled or could not be found.
In the standard InterSystems IRIS implementation, it is not directly possible to execute the command in a directory of the operating system. The directory in which the operating system command is to be executed can be specified.
USER>write $System.Status.GetErrorText(##class(arsblue.util.Exec).Call("dir","C:\InterSystems\IRIS\mgr\stream",,$IO,$IO))
Volume in Laufwerk C: hat keine Bezeichnung.
Volumeseriennummer: F0D2-A330
Verzeichnis von C:\InterSystems\IRIS\mgr\stream
28.09.2018 16:57 <DIR> .
28.09.2018 16:57 <DIR> ..
0 Datei(en), 0 Bytes
2 Verzeichnis(se), 94 609 014 784 Bytes frei
In the standard InterSystems IRIS implementation, it is not directly possible to specify a function to be executed after the operating system command. The difference to editing in the calling function is the direct access to the parameters used in the call.
Callback Definition:
Class User.TestCallback [ Abstract ]
{
ClassMethod ExecCallback(params...)
{
// kill process callback information
kill ^callback(%pid)
// copy all process parameters
set ^callback(%pid,$I(^callback(%pid)))="PARAMS:"
merge ^callback(%pid,$I(^callback(%pid)))=params
// save process output
set ^callback(%pid,$I(^callback(%pid)))="STDOUT:"
do %out.Rewind()
while ('%out.AtEnd)
{
set ^callback(%pid,$I(^callback(%pid)))=%out.ReadLine()
}
// save process error
set ^callback(%pid,$I(^callback(%pid)))="STDERR:"
do %err.Rewind()
while ('%err.AtEnd)
{
set ^callback(%pid,$I(^callback(%pid)))=%err.ReadLine()
}
}
}
Callback Sample:
USER>write $System.Status.GetErrorText(##class(arsblue.util.Exec).Call("dir",,,,,,.pid,"User.TestCallback.ExecCallback","A","B","C",1,2,3))
USER>zw ^callback(pid)
^callback(21408)=17
^callback(21408,1)="PARAMS:"
^callback(21408,2)=6
^callback(21408,2,1)="A"
^callback(21408,2,2)="B"
^callback(21408,2,3)="C"
^callback(21408,2,4)=1
^callback(21408,2,5)=2
^callback(21408,2,6)=3
^callback(21408,3)="STDOUT:"
^callback(21408,4)=" Volume in Laufwerk C: hat keine Bezeichnung."
^callback(21408,5)=" Volumeseriennummer: F0D2-A330"
^callback(21408,6)=""
^callback(21408,7)=" Verzeichnis von c:\intersystems\iris\mgr\user"
^callback(21408,8)=""
^callback(21408,9)="01.05.2019 14:30 <DIR> ."
^callback(21408,10)="01.05.2019 14:30 <DIR> .."
^callback(21408,11)="12.04.2019 10:27 5 209 325 568 IRIS.DAT"
^callback(21408,12)="17.04.2019 08:56 46 iris.lck"
^callback(21408,13)="28.09.2018 16:57 <DIR> stream"
^callback(21408,14)=" 2 Datei(en), 5 209 325 614 Bytes"
^callback(21408,15)=" 3 Verzeichnis(se), 94 259 175 424 Bytes frei"
^callback(21408,16)="STDERR:"
^callback(21408,17)=""
In the standard InterSystems IRIS implementation, it is not directly possible to query the status of an operating system command executed in the background (separate process). The process number can be queried directly.
USER>write $System.Status.GetErrorText(##class(arsblue.util.Exec).Call("dir /S /B >NUL","C:\InterSystems\IRIS",,,,1,.pid)),!,"pid=",pid
pid=28636
USER>while (##class(arsblue.util.Exec).IsProcessRunning(pid)) { write "." } write "finished"
......finished
In the standard InterSystems IRIS implementation, it is not directly possible to respond to an operating system command that runs in the background. The callback function allows you to execute commands in InterSystems IRIS after the operating system command completes in the background.
USER>write $System.Status.GetErrorText(##class(arsblue.util.Exec).Call("dir",,,,,1,.pid,"User.TestCallback.ExecCallback","A","B","C",1,2,3))
USER>zw ^callback(pid)
^callback(1832)=17
^callback(1832,1)="PARAMS:"
^callback(1832,2)=6
^callback(1832,2,1)="A"
^callback(1832,2,2)="B"
^callback(1832,2,3)="C"
^callback(1832,2,4)=1
^callback(1832,2,5)=2
^callback(1832,2,6)=3
^callback(1832,3)="STDOUT:"
^callback(1832,4)=" Volume in Laufwerk C: hat keine Bezeichnung."
^callback(1832,5)=" Volumeseriennummer: F0D2-A330"
^callback(1832,6)=""
^callback(1832,7)=" Verzeichnis von c:\intersystems\iris\mgr\user"
^callback(1832,8)=""
^callback(1832,9)="01.05.2019 14:30 <DIR> ."
^callback(1832,10)="01.05.2019 14:30 <DIR> .."
^callback(1832,11)="12.04.2019 10:27 5 209 325 568 IRIS.DAT"
^callback(1832,12)="17.04.2019 08:56 46 iris.lck"
^callback(1832,13)="28.09.2018 16:57 <DIR> stream"
^callback(1832,14)=" 2 Datei(en), 5 209 325 614 Bytes"
^callback(1832,15)=" 3 Verzeichnis(se), 94 599 979 008 Bytes frei"
^callback(1832,16)="STDERR:"
^callback(1832,17)=""
Many functions already exist in the standard InterSystems IRIS JSON implementation. The functions described here combine some of the functions or expand them for improved handling of JSON objects. On the one hand the functions of the class arsblue.util.Json
are available and on the other hand there is the corresponding macro arsblue.util.Json
in order to be able to use the most important functions of the class in shortened notation in the source code. In the following, the functions are always described with the equivalent macro (if any).
To be able to use the macro in your own source code, it is necessary to include it in the first line of the class.
Include (arsblue.util.Json)
/// my class
Class my.Class {
...
}
Syntax:
##class(arsblue.util.Json).IndexOf(<JSON-Array-Oder-Objekt>,<Wert>[,<Start-Index>])
Macro:
$$$JSON.IndexOf(<JSON-Array-Oder-Objekt>,<Wert>[,<Start-Index>])
By default, the search returns the index where the value occurs first. The optional parameter Start-Index
can be used to search for further occurrences. If no index for a value is found, an empty string is returned.
JSON Array:
USER>set array=["a","b","a","c","a","d"]
USER>write ##class(arsblue.util.Json).IndexOf(array,"a")
0
USER>write ##class(arsblue.util.Json).IndexOf(array,"a",0)
2
USER>write ##class(arsblue.util.Json).IndexOf(array,"a",2)
4
USER>write ##class(arsblue.util.Json).IndexOf(array,"a",4)
JSON Object:
USER>set object={"key0":"a","key1":"b","key2":"a","key3":"c","key4":"a","key5":"d"}
USER>write ##class(arsblue.util.Json).IndexOf(object,"a")
key0
USER>write ##class(arsblue.util.Json).IndexOf(object,"a","key0")
key2
USER>write ##class(arsblue.util.Json).IndexOf(object,"a","key2")
key4
USER>write ##class(arsblue.util.Json).IndexOf(object,"a","key4")
Syntax:
##class(arsblue.util.Json).Copy(<JSON-Quell-Array-Oder-Objekt>,<JSON-Ziel-Array-Oder-Objekt>[,<Bedingung>])
Macro:
$$$JSON.Copy(<JSON-Quell-Array-Oder-Objekt>,<JSON-Ziel-Array-Oder-Objekt>[,<Bedingung>])
With this function, JSON arrays or objects can be copied or linked. If an empty destination array or object is specified, it is a pure copy function. If a non-empty target array or object is specified, the data in the destination is connected to the data of the source. The way the data is connected can be specified by the condition.
Condition | Description |
---|---|
0 (Default) | Copies all data from the source and overwrites the data in the destination if necessary. |
1 | Copies only those data of the source that are not present in the destination. |
2 | Copies only those data of the source, which exist in the destination and overwrites these. |
USER>set source={"array":[1,2,3],"object":{"a":"b","c":"d"}},target=""
USER>write $System.Status.GetErrorText(##class(arsblue.util.Json).Copy(source,.target))
USER>write target.%ToJSON()
{"array":[1,2,3],"object":{"a":"b","c":"d"}}
This condition creates a depth copy. The advantage over the variant proposed by InterSystems IRIS (set target={}.%FromJson(source.% ToJson())
) is that object references are copied, which in the InterSystems IRIS standard case are not exported to JSON and thus no longer can be imported from JSON.
USER>set source={"array":[1,2,3],"object":{"a":"b","c":"d"}},target={"array":[3,4,5],"object":{"a":"x","b":"z"}}
USER>write $System.Status.GetErrorText(##class(arsblue.util.Json).Copy(source,.target,0))
USER>write target.%ToJSON()
{"array":[1,2,3],"object":{"a":"b","b":"z","c":"d"}}
With this condition JSON arrays are completely replaced, in JSON objects the data is only overwritten.
USER>set source={"array":[1,2,3],"object":{"a":"b","c":"d"}},target={"array":[3,4,5],"object":{"a":"x","b":"z"}}
USER>write $System.Status.GetErrorText(##class(arsblue.util.Json).Copy(source,.target,1))
USER>write target.%ToJSON()
{"array":[3,4,5,1,2],"object":{"a":"x","b":"z","c":"d"}}
In this condition, non-existent values are added to JSON arrays at the end; JSON objects will only insert non-existent data.
USER>set source={"array":[1,2,3],"object":{"a":"b","c":"d"}},target={"array":[3,4,5],"object":{"a":"x","b":"z"}}
USER>write $System.Status.GetErrorText(##class(arsblue.util.Json).Copy(source,.target,2))
USER>write target.%ToJSON()
{"array":[3,4,5],"object":{"a":"b","b":"z"}}
With this condition, JSON arrays remain untouched; in JSON objects, only existing data is overwritten.
Syntax:
##class(arsblue.util.Json).Equals(<JSON-Array-Oder-Objekt>,<JSON-Vergleichs-Array-Oder-Objekt>)
Macro:
$$$JSON.Equals(<JSON-Array-Oder-Objekt>,<JSON-Vergleichs-Array-Oder-Objekt>)
With this function, JSON arrays or objects can be checked for equality.
USER>set json1={"a":[{"b":"c"},1,2,3]},json2={"a":[{"b":"c"},1,2,3]}
USER>write ##class(arsblue.util.Json).Equals(json1,json2)
1
USER>set json1={"a":[{"b":"c"},1,2,3]},json2={"a":[{"b":"c","d":"e"},1,2,3]}
USER>write ##class(arsblue.util.Json).Equals(json1,json2)
0
USER>set json1={"a":[{"b":"c"},1,2,3,4,5]},json2={"a":[{"b":"c"},1,2,3]}
USER>write ##class(arsblue.util.Json).Equals(json1,json2)
0
All levels of the two JSON arrays or objects are compared. The advantage over the variant proposed by InterSystems IRIS (set equals=(json1.% ToJSON()=json2.%ToJSON())
) is that object references are compared, which in the InterSystems IRIS standard case are not exported to JSON and thus can not be compared. Furthermore, the IRIS JSON export takes into account the order of creation of the values, so it is not possible to check whether a JSON object (which depends only on the content and not the order - as in the JSON array) really does is equal to.
USER>set json1={"a":"b","c":"d"},json2={"c":"d","a":"b"}
USER>write json1.%ToJSON(),!,json2.%ToJSON()
{"a":"b","c":"d"}
{"c":"d","a":"b"}
USER>write json1.%ToJSON()=json2.%ToJSON()
0
USER>write ##class(arsblue.util.Json).Equals(json1,json2)
1
Syntax:
##class(arsblue.util.Json).Diff(<JSON-Array-Oder-Objekt>,<JSON-Vergleichs-Array-Oder-Objekt>)
Macro:
$$$JSON.Diff(<JSON-Array-Oder-Objekt>,<JSON-Vergleichs-Array-Oder-Objekt>)
This function can be used to compare JSON arrays or objects.
USER>set json1={"a":"b","c":["d","e","f"]},json2={"c":["d","e","f"],"a":"b"}
USER>write ##class(arsblue.util.Json).Diff(json1,json2)
USER>set json1={"a":"b","c":["d","E","f"]},json2={"c":["d","e","f"],"a":"B"}
USER>write ##class(arsblue.util.Json).Diff(json1,json2).%ToJSON()
{"a":["b","B"],"c":[null,["E","e"]]}
All levels of the two JSON arrays or objects are compared. If no JSON array or object is returned, the two JSON arrays or objects are identical; otherwise, in the returned JSON array or object, those values are defined as JSON array ([<value-1>,<value-2>]
) that have changed (in a JSON array, null
means that the value at this index has not changed, but there is an index behind it that contains a change).
Syntax:
##class(arsblue.util.Json).GetJSONFromObject(<Objektreferenz>,<Exportierte-JSON-Objektreferenz>[,<Alle-Daten-exportieren>][,<ID/GUID-nicht-exportieren>][,<Transiente-Daten-exportieren>])
##class(arsblue.util.Json).GetJSONFromExtent(<Objekt-ID>,<Exportierte-JSON-Objektreferenz>[,<Alle-Daten-exportieren>][,<ID/GUID-nicht-exportieren>])
Macro:
$$$JSON.GetJSONFromObject(<Objektreferenz>,<Exportierte-JSON-Objektreferenz>[,<Alle-Daten-exportieren>][,<ID/GUID-nicht-exportieren>][,<Transiente-Daten-exportieren>])
$$$JSON.GetJSONFromExtent(<Objekt-ID>,<Exportierte-JSON-Objektreferenz>[,<Alle-Daten-exportieren>][,<ID/GUID-nicht-exportieren>])
With these functions, data objects can be exported to JSON. The difference between the two methods is that the GetJSONFromObject
method works with the loaded object references in memory, whereas GetJSONFromExtent
works with the data in the respective object global. The InterSystems IRIS architecture is designed to load a data object only once, i.e. no matter how many times an object is loaded with the same object id, it always points to the same object reference in memory (with all its changes already made). This is sometimes not desirable and the application wants to know what is actually still in the object global or what changes are already available in the object world. For this, the possibility was created to read this data as JSON directly from the Extent.
With the GetJSONFromObject
method, all object references stored in memory can be exported to JSON. It is not mandatory that these are persistable data, only that they are derived from %Library.RegisteredObject
.
The programmer can decide if he wants to export all data or just the "header" data (ie class, ID and if available GUID).
The programmer can decide if he wants to export all data except the "header" data. This option is particularly interesting if you need to communicate with third-party systems that are not necessarily aware of internal class names and ID's.
The programmer can decide if he also wants to export transient data. Of course, this option is not available for GetJSONFromExtent
because only non-transient data can be exported here.
Syntax:
##class(arsblue.util.Json).GetObjectFromJSON(<JSON-Objekt>,<Importierte-Objektreferenz>[,<Alle-Daten-importieren>][,<ID/GUID-nicht-importieren>][,<Transiente-Daten-importieren>])
Macro:
$$$JSON.GetObjectFromJSON(<JSON-Objekt>,<Importierte-Objektreferenz>[,<Alle-Daten-importieren>][,<ID/GUID-nicht-importieren>][,<Transiente-Daten-importieren>])
With this function, data objects can be imported from JSON. The object references are loaded (if data objects) and changed accordingly but not saved (if data objects). The memory of the data objects is the responsibility of the programmer. In principle, all classes derived from %Library.RegisteredObject
can be imported.
The developer can decide if he wants to import all the data or just the "header" data (i.e. class, ID and if available GUID). This corresponds to an availability check, as it is only possible to check whether a data object can be loaded with the given "header" data.
The programmer can decide if he wants to import all data except the "header" data. This option is especially interesting when you need to make copies of data, i.e. an export with subsequent import without "header" data creates a copy of the exported data (if automatic IDs are used).
The programmer can decide if he also wants to import transient data.
Syntax:
##class(arsblue.util.Json).GetJSONFromList(<$LIST>)
##class(arsblue.util.Json).GetListFromJSON(<JSON-Array>)
Macro:
$$$JSON.GetJSONFromList(<$LIST>)
$$$JSON.GetListFromJSON(<JSON-Array>)
With these functions a $LIST
can be used to create a JSON array or from a JSON array a $LIST
.
USER>set list=$LISTBUILD("a","b","c",$LISTBUILD(1,2,3))
USER>write ##class(arsblue.util.Json).GetJSONFromList(list).%ToJSON()
["a","b","c",[1,2,3]]
USER>set json=["a","b","c",[1,2,3]]
USER>zwrite ##class(arsblue.util.Json).GetListFromJSON(json)
$lb("a","b","c",$lb(1,2,3))
Syntax:
##class(arsblue.util.Json).GetJSONFromStatus(<Status>)
##class(arsblue.util.Json).GetStatusFromJSON(<JSON-Objekt>)
Macro:
$$$JSON.GetJSONFromStatus(<Status>)
$$$JSON.GetStatusFromJSON(<JSON-Objekt>)
These functions can be used to create a JSON object from a %Library.Status
or a %Library.Status
from a JSON object.
USER>set status=$System.Status.Error(5001,"This is an error!")
USER>write ##class(arsblue.util.Json).GetJSONFromStatus(status).%ToJSON()
{"_ClassName":"%Library.Status","_Status":[[5001,"This is an error!",null,null,null,null,null,null,null,[null,"USER",["e^zError+1^%SYSTEM.Status.1^1","e^^^0"]]]]}
USER>set json={"_ClassName":"%Library.Status","_Status":[[5001,"This is an error!",null,null,null,null,null,null,null,[null,"USER",["e^zError+1^%SYSTEM.Status.1^1","e^^^0"]]]]}
USER>write $System.Status.GetErrorText(##class(arsblue.util.Json).GetStatusFromJSON(json))
FEHLER #5001: This is an error!
Syntax:
##class(arsblue.util.Json).%FromJSON(<Zeichenkette-Oder-Datenstrom>)
Macro:
$$$JSON.%FromJSON(<Zeichenkette-Oder-Datenstrom>)
With this function JSON can be read from a string or a data stream. The difference to the standard InterSystems IRIS implementation is that both strict and non-strict JSON syntax (object keywords with or without single quotes), single-line as well as multi-line comments and JavaScript functions (stored as data stream objects) are allowed. The limitation is that the object keywords always have to be at the beginning of a new line (spaces and tabs are ignored).
Syntax:
##class(arsblue.util.Json).%ToJSON(<JSON-Array-Oder-Objekt>,<Ausgabedatenstrom-Objektreferenz>[,<Einrückungszeichen>][,<Einrückungsebene>])
Macro:
$$$JSON.%ToJSON(<JSON-Array-Oder-Objekt>,<Ausgabedatenstrom-Objektreferenz>[,<Einrückungszeichen>][,<Einrückungsebene>])
This feature allows JSON to be written to an output stream. The output is automatically formatted. The formatting can be adjusted with the additional parameters. The standard InterSystems IRIS implementation (% ZEN.Auxiliary.jsonProvider
) unfortunately has an incorrect or incomplete implementation for some data types.
USER>set json={"a":"b","c":[1,2,3]}
USER>do ##class(arsblue.util.Json).%ToJSON(json)
{
"a": "b",
"c": [
1,
2,
3
]
}