1
0
Fork 0
libreoffice/wizards/source/scriptforge/SF_Region.xba
Daniel Baumann 8e63e14cf6
Adding upstream version 4:25.2.3.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
2025-06-22 16:20:04 +02:00

861 lines
No EOL
42 KiB
XML

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE script:module PUBLIC "-//OpenOffice.org//DTD OfficeDocument 1.0//EN" "module.dtd">
<script:module xmlns:script="http://openoffice.org/2000/script" script:name="SF_Region" script:language="StarBasic" script:moduleType="normal">REM =======================================================================================================================
REM === The ScriptForge library and its associated libraries are part of the LibreOffice project. ===
REM === Full documentation is available on https://help.libreoffice.org/ ===
REM =======================================================================================================================
Option Compatible
Option Explicit
&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;
&apos;&apos;&apos; SF_Region
&apos;&apos;&apos; =========
&apos;&apos;&apos; Singleton class implementing the &quot;ScriptForge.Region&quot; service
&apos;&apos;&apos; Implemented as a usual Basic module
&apos;&apos;&apos;
&apos;&apos;&apos; A collection of functions about languages, countries and timezones
&apos;&apos;&apos; - Locales
&apos;&apos;&apos; - Currencies
&apos;&apos;&apos; - Numbers and dates formatting
&apos;&apos;&apos; - Calendars
&apos;&apos;&apos; - Timezones conversions
&apos;&apos;&apos; - Numbers transformed to text
&apos;&apos;&apos;
&apos;&apos;&apos; Definitions:
&apos;&apos;&apos; Locale or Region
&apos;&apos;&apos; A combination of a language (2 or 3 lower case characters) and a country (2 upper case characters)
&apos;&apos;&apos; Most properties and methods require a locale as argument.
&apos;&apos;&apos; Some of them accept either the complete locale or only the language or country parts.
&apos;&apos;&apos; When absent, the considered locale is the locale used in the LibreOffice user interface.
&apos;&apos;&apos; (see the SF_Platform.OfficeLocale property)
&apos;&apos;&apos; Timezone
&apos;&apos;&apos; Specified as &quot;Region/City&quot; name like &quot;Europe/Berlin&quot;, or a custom time zone ID such as &quot;UTC&quot; or &quot;GMT-8:00&quot;.
&apos;&apos;&apos; The time offset between the timezone and the Greenwich Meridian Time (GMT) is expressed in minutes.
&apos;&apos;&apos; The Daylight Saving Time (DST) is an additional offset.
&apos;&apos;&apos; Both offsets can be positive or negative.
&apos;&apos;&apos; More info on
&apos;&apos;&apos; https://timezonedb.com/time-zones
&apos;&apos;&apos; https://en.wikipedia.org/wiki/Time_zone
&apos;&apos;&apos;
&apos;&apos;&apos; Service invocation example:
&apos;&apos;&apos; Dim regio As Object
&apos;&apos;&apos; Set regio = CreateScriptService(&quot;Region&quot;)
&apos;&apos;&apos;
&apos;&apos;&apos; Detailed user documentation:
&apos;&apos;&apos; https://help.libreoffice.org/latest/en-US/text/sbasic/shared/03/sf_region.html?DbPAR=BASIC
&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;&apos;
REM ================================================================== EXCEPTIONS
REM ============================================================= PRIVATE MEMBERS
Private UserLocale As String &apos; platform.OfficeLocale
&apos; Reference tables
Private LocaleData As Variant &apos; com.sun.star.i18n.LocaleData
Private LocaleNames As Variant &apos; Array of all available &quot;la-CO&quot; strings
Private UserIndex As Integer &apos; Index of UserLocale in reference tables
REM ============================================================ MODULE CONSTANTS
REM ===================================================== CONSTRUCTOR/DESTRUCTOR
REM -----------------------------------------------------------------------------
Public Function Dispose() As Variant
Set Dispose = Nothing
End Function &apos; ScriptForge.SF_Region Explicit destructor
REM ================================================================== PROPERTIES
REM -----------------------------------------------------------------------------
Property Get Country(Optional ByVal Region As Variant) As String
&apos;&apos;&apos; Returns the english country name applicable in the given region.
&apos;&apos;&apos; The region expressed either as a
&apos;&apos;&apos; - locale combining language-COUNTRY (la-CO)
&apos;&apos;&apos; - country only (CO)
&apos;&apos;&apos; Example:
&apos;&apos;&apos; MsgBox Regio.Country(&quot;IT&quot;) &apos; Italy
Country = _PropertyGet(&quot;Country&quot;, Region)
End Property &apos; ScriptForge.SF_Region.Country (get)
REM -----------------------------------------------------------------------------
Property Get Currency(Optional ByVal Region As Variant) As String
&apos;&apos;&apos; Returns the currency applicable in the given region.
&apos;&apos;&apos; The region is expressed either as a
&apos;&apos;&apos; - locale combining language-COUNTRY (la-CO)
&apos;&apos;&apos; - country only (CO)
&apos;&apos;&apos; Example:
&apos;&apos;&apos; MsgBox Regio.Currency(&quot;IT&quot;) &apos; EUR
Currency = _PropertyGet(&quot;Currency&quot;, Region)
End Property &apos; ScriptForge.SF_Region.Currency (get)
REM -----------------------------------------------------------------------------
Public Function DatePatterns(Optional ByVal Region As Variant) As Variant &apos; Function better than Property when return value is an array
&apos;&apos;&apos; Returns list of date acceptance patterns for the given region.
&apos;&apos;&apos; Patterns with input combinations that are accepted as incomplete date input, such as M/D or D.M
&apos;&apos;&apos; The region is expressed as a locale combining language-COUNTRY (la-CO)
&apos;&apos;&apos; The list is zero-based.
&apos;&apos;&apos; Example:
&apos;&apos;&apos; MsgBox Join(Regio.DatePatterns(&quot;it-IT&quot;), &quot;,&quot;) &apos; D/M/Y,D/M
DatePatterns = _PropertyGet(&quot;DatePatterns&quot;, Region)
End Function &apos; ScriptForge.SF_Region.DatePatterns (get)
REM -----------------------------------------------------------------------------
Property Get DateSeparator(Optional ByVal Region As Variant) As String
&apos;&apos;&apos; Returns the separator used in dates applicable in the given region.
&apos;&apos;&apos; The region is expressed as a locale combining language-COUNTRY (la-CO)
&apos;&apos;&apos; Example:
&apos;&apos;&apos; MsgBox Regio.DateSeparator(&quot;it-IT&quot;) &apos; /
DateSeparator = _PropertyGet(&quot;DateSeparator&quot;, Region)
End Property &apos; ScriptForge.SF_Region.DateSeparator (get)
REM -----------------------------------------------------------------------------
Public Function DayAbbrevNames(Optional ByVal Region As Variant) As Variant &apos; Function better than Property when return value is an array
&apos;&apos;&apos; Returns list of abbreviated names of weekdays applicable in the given region.
&apos;&apos;&apos; The region expressed as a
&apos;&apos;&apos; - locale combining language-COUNTRY (la-CO)
&apos;&apos;&apos; - language only (la)
&apos;&apos;&apos; The list is zero-based. The 1st in the list [0] is the Monday.
&apos;&apos;&apos; Example:
&apos;&apos;&apos; MsgBox Join(Regio.DayAbbrevNames(&quot;it-IT&quot;), &quot;,&quot;) &apos; lun,mar,mer,gio,ven,sab,dom
DayAbbrevNames = _PropertyGet(&quot;DayAbbrevNames&quot;, Region)
End Function &apos; ScriptForge.SF_Region.DayAbbrevNames (get)
REM -----------------------------------------------------------------------------
Public Function DayNames(Optional ByVal Region As Variant) As Variant &apos; Function better than Property when return value is an array
&apos;&apos;&apos; Returns list of names of weekdays applicable in the given region.
&apos;&apos;&apos; The region expressed as a
&apos;&apos;&apos; - locale combining language-COUNTRY (la-CO)
&apos;&apos;&apos; - language only (la)
&apos;&apos;&apos; The list is zero-based. The 1st in the list [0] is the Monday.
&apos;&apos;&apos; Example:
&apos;&apos;&apos; MsgBox Join(Regio.DayNames(&quot;it-IT&quot;), &quot;,&quot;) &apos; lunedì,martedì,mercoledì,giovedì,venerdì,sabato,domenica
DayNames = _PropertyGet(&quot;DayNames&quot;, Region)
End Function &apos; ScriptForge.SF_Region.DayNames (get)
REM -----------------------------------------------------------------------------
Public Function DayNarrowNames(Optional ByVal Region As Variant) As Variant &apos; Function better than Property when return value is an array
&apos;&apos;&apos; Returns list of initials of weekdays applicable in the given region.
&apos;&apos;&apos; The region expressed as a
&apos;&apos;&apos; - locale combining language-COUNTRY (la-CO)
&apos;&apos;&apos; - language only (la)
&apos;&apos;&apos; The list is zero-based. The 1st in the list [0] is the Monday.
&apos;&apos;&apos; Example:
&apos;&apos;&apos; MsgBox Join(Regio.DayNarrowNames(&quot;it-IT&quot;), &quot;,&quot;) &apos; l,m,m,g,v,s,d
DayNarrowNames = _PropertyGet(&quot;DayNarrowNames&quot;, Region)
End Function &apos; ScriptForge.SF_Region.DayNarrowNames (get)
REM -----------------------------------------------------------------------------
Property Get DecimalPoint(Optional ByVal Region As Variant) As String
&apos;&apos;&apos; Returns the decimal separator used in numbers applicable in the given region.
&apos;&apos;&apos; The region is expressed as a locale combining language-COUNTRY (la-CO)
&apos;&apos;&apos; Example:
&apos;&apos;&apos; MsgBox Regio.DecimalPoint(&quot;it-IT&quot;) &apos; .
DecimalPoint = _PropertyGet(&quot;DecimalPoint&quot;, Region)
End Property &apos; ScriptForge.SF_Region.DecimalPoint (get)
REM -----------------------------------------------------------------------------
Property Get Language(Optional ByVal Region As Variant) As String
&apos;&apos;&apos; Returns the english Language name applicable in the given region.
&apos;&apos;&apos; The region expressed as a
&apos;&apos;&apos; - locale combining language-COUNTRY (la-CO)
&apos;&apos;&apos; - language only (la)
&apos;&apos;&apos; Example:
&apos;&apos;&apos; MsgBox Regio.Language(&quot;it-IT&quot;) &apos; Italian
Language = _PropertyGet(&quot;Language&quot;, Region)
End Property &apos; ScriptForge.SF_Region.Language (get)
REM -----------------------------------------------------------------------------
Property Get ListSeparator(Optional ByVal Region As Variant) As String
&apos;&apos;&apos; Returns the separator used in lists applicable in the given region.
&apos;&apos;&apos; The region is expressed as a locale combining language-COUNTRY (la-CO)
&apos;&apos;&apos; Example:
&apos;&apos;&apos; MsgBox Regio.ListSeparator(&quot;it-IT&quot;) &apos; ;
ListSeparator = _PropertyGet(&quot;ListSeparator&quot;, Region)
End Property &apos; ScriptForge.SF_Region.ListSeparator (get)
REM -----------------------------------------------------------------------------
Public Function MonthAbbrevNames(Optional ByVal Region As Variant) As Variant &apos; Function better than Property when return value is an array
&apos;&apos;&apos; Returns list of abbreviated names of months applicable in the given region.
&apos;&apos;&apos; The region expressed as a
&apos;&apos;&apos; - locale combining language-COUNTRY (la-CO)
&apos;&apos;&apos; - language only (la)
&apos;&apos;&apos; The list is zero-based.
&apos;&apos;&apos; Example:
&apos;&apos;&apos; MsgBox Join(Regio.MonthAbbrevNames(&quot;it-IT&quot;), &quot;,&quot;) &apos; gen,feb,mar,apr,mag,giu,lug,ago,set,ott,nov,dic
MonthAbbrevNames = _PropertyGet(&quot;MonthAbbrevNames&quot;, Region)
End Function &apos; ScriptForge.SF_Region.MonthAbbrevNames (get)
REM -----------------------------------------------------------------------------
Public Function MonthNames(Optional ByVal Region As Variant) As Variant &apos; Function better than Property when return value is an array
&apos;&apos;&apos; Returns list of names of months applicable in the given region.
&apos;&apos;&apos; The region expressed as a
&apos;&apos;&apos; - locale combining language-COUNTRY (la-CO)
&apos;&apos;&apos; - language only (la)
&apos;&apos;&apos; The list is zero-based.
&apos;&apos;&apos; Example:
&apos;&apos;&apos; MsgBox Join(Regio.MonthNames(&quot;it-IT&quot;), &quot;,&quot;) &apos; gennaio,febbraio,marzo,aprile,maggio,giugno,luglio,agosto,settembre,ottobre,novembre,dicembre
MonthNames = _PropertyGet(&quot;MonthNames&quot;, Region)
End Function &apos; ScriptForge.SF_Region.MonthNames (get)
REM -----------------------------------------------------------------------------
Public Function MonthNarrowNames(Optional ByVal Region As Variant) As Variant &apos; Function better than Property when return value is an array
&apos;&apos;&apos; Returns list of initials of months applicable in the given region.
&apos;&apos;&apos; The region expressed as a
&apos;&apos;&apos; - locale combining language-COUNTRY (la-CO)
&apos;&apos;&apos; - language only (la)
&apos;&apos;&apos; The list is zero-based.
&apos;&apos;&apos; Example:
&apos;&apos;&apos; MsgBox Join(Regio.MonthNarrowNames(&quot;it-IT&quot;), &quot;,&quot;) &apos; g,f,m,a,m,g,l,a,s,o,n,d
MonthNarrowNames = _PropertyGet(&quot;MonthNarrowNames&quot;, Region)
End Function &apos; ScriptForge.SF_Region.MonthNarrowNames (get)
REM -----------------------------------------------------------------------------
Property Get ObjectType As String
&apos;&apos;&apos; Only to enable object representation
ObjectType = &quot;SF_Region&quot;
End Property &apos; ScriptForge.SF_Region.ObjectType
REM -----------------------------------------------------------------------------
Property Get ServiceName As String
&apos;&apos;&apos; Internal use
ServiceName = &quot;ScriptForge.Region&quot;
End Property &apos; ScriptForge.SF_Region.ServiceName
REM -----------------------------------------------------------------------------
Property Get ThousandSeparator(Optional ByVal Region As Variant) As String
&apos;&apos;&apos; Returns the thousands separator used in numbers applicable in the given region.
&apos;&apos;&apos; The region is expressed as a locale combining language-COUNTRY (la-CO)
&apos;&apos;&apos; Example:
&apos;&apos;&apos; MsgBox Regio.ThousandSeparator(&quot;it-IT&quot;) &apos; .
ThousandSeparator = _PropertyGet(&quot;ThousandSeparator&quot;, Region)
End Property &apos; ScriptForge.SF_Region.ThousandSeparator (get)
REM -----------------------------------------------------------------------------
Property Get TimeSeparator(Optional ByVal Region As Variant) As String
&apos;&apos;&apos; Returns the separator used to format times applicable in the given region.
&apos;&apos;&apos; The region is expressed as a locale combining language-COUNTRY (la-CO)
&apos;&apos;&apos; Example:
&apos;&apos;&apos; MsgBox Regio.TimeSeparator(&quot;it-IT&quot;) &apos; :
TimeSeparator = _PropertyGet(&quot;TimeSeparator&quot;, Region)
End Property &apos; ScriptForge.SF_Region.TimeSeparator (get)
REM ===================================================================== METHODS
REM -----------------------------------------------------------------------------
Public Function DSTOffset(Optional ByVal LocalDateTime As Variant _
, Optional ByVal TimeZone As Variant _
, Optional ByVal Locale As Variant _
) As Integer
&apos;&apos;&apos; Computes the additional offset due to daylight saving (&quot;summer time&quot;)
&apos;&apos;&apos; Args
&apos;&apos;&apos; LocalDateTime: local date and time as a Date. DST offset varies during the year.
&apos;&apos;&apos; TimeZone: specified as &quot;Region/City&quot; name like &quot;Europe/Berlin&quot;, or a custom time zone ID such as &quot;UTC&quot; or &quot;GMT-8:00&quot;
&apos;&apos;&apos; Locale: expressed as a locale combining language-COUNTRY (la-CO), or COUNTRY alone (CO)
&apos;&apos;&apos; Return:
&apos;&apos;&apos; The offset in minutes
&apos;&apos;&apos; Examples:
&apos;&apos;&apos; regio.DSTOffset(DateSerial(2022, 8, 20) + TimeSerial(16, 58, 17), &quot;Europe/Brussels&quot;, &quot;fr-BE&quot;) &apos; 60
Dim iDSTOffset As Integer &apos; Return value
Dim oLocale As Object &apos; com.sun.star.lang.Locale
Dim oCalendarImpl As Object &apos; com.sun.star.i18n.CalendarImpl
Const cstThisSub = &quot;Region.DSTOffset&quot;
Const cstSubArgs = &quot;LocalDateTime, TimeZone, [Locale=&quot;&quot;&quot;&quot;]&quot;
If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
iDSTOffset = 0
Check:
If IsMissing(Locale) Or IsEmpty(Locale) Then Locale = &quot;&quot;
If SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
If Not SF_Utils._Validate(LocalDateTime, &quot;LocalDateTime&quot;, V_DATE) Then GoTo Finally
If Not SF_Utils._Validate(TimeZone, &quot;TimeZone&quot;, V_STRING) Then GoTo Finally
If Not SF_Utils._Validate(Locale, &quot;Locale&quot;, V_STRING) Then GoTo Finally
End If
Set oLocale = SF_Region._GetLocale(Locale, pbCountry := True)
If IsNull(oLocale) Then GoTo Finally
Try:
Set oCalendarImpl = SF_Utils._GetUNOService(&quot;CalendarImpl&quot;)
With oCalendarImpl
.loadDefaultCalendarTZ(oLocale, TimeZone)
.setLocalDateTime(LocaldateTime)
iDSTOffset = .getValue(com.sun.star.i18n.CalendarFieldIndex.DST_OFFSET)
End With
Finally:
DSTOffset = iDSTOffset
SF_Utils._ExitFunction(cstThisSub)
Exit Function
Catch:
GoTo Finally
End Function &apos; ScriptForge.SF_Region.DSTOffset
REM -----------------------------------------------------------------------------
Public Function GetProperty(Optional ByVal PropertyName As Variant _
, Optional Region As Variant _
) As Variant
&apos;&apos;&apos; Return the actual value of the given property
&apos;&apos;&apos; Args:
&apos;&apos;&apos; PropertyName: the name of the property as a string
&apos;&apos;&apos; Region: the language-COUNTRY combination (la-CO) or the country (CO- or the language (la)
&apos;&apos;&apos; Returns:
&apos;&apos;&apos; The actual value of the property
&apos;&apos;&apos; Exceptions:
&apos;&apos;&apos; ARGUMENTERROR The property does not exist
Const cstThisSub = &quot;Region.GetProperty&quot;
Const cstSubArgs = &quot;&quot;
If ScriptForge.SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
GetProperty = Null
Check:
If IsMissing(Region) Or IsEmpty(Region) Then Region = &quot;&quot;
If ScriptForge.SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
If Not ScriptForge.SF_Utils._Validate(PropertyName, &quot;PropertyName&quot;, V_STRING, Properties()) Then GoTo Catch
If Not ScriptForge.SF_Utils._Validate(Region, &quot;Region&quot;, V_STRING) Then GoTo Catch
End If
Try:
If Len(Region) = 0 Then
GetProperty = _PropertyGet(PropertyName)
Else
GetProperty = _PropertyGet(PropertyName, Region)
End If
Finally:
SF_Utils._ExitFunction(cstThisSub)
Exit Function
Catch:
GoTo Finally
End Function &apos; ScriptForge.SF_Region.GetProperty
REM -----------------------------------------------------------------------------
Public Function LocalDateTime(Optional ByVal UTCDateTime As Variant _
, Optional ByVal TimeZone As Variant _
, Optional ByVal Locale As Variant _
) As Date
&apos;&apos;&apos; Computes the local date and time from a UTC date and time
&apos;&apos;&apos; Args
&apos;&apos;&apos; UTCDateTime: the universal date and time to be converted to local time
&apos;&apos;&apos; TimeZone: specified as &quot;Region/City&quot; name like &quot;Europe/Berlin&quot;, or a custom time zone ID such as &quot;UTC&quot; or &quot;GMT-8:00&quot;
&apos;&apos;&apos; Locale: expressed as a locale combining language-COUNTRY (la-CO), or COUNTRY alone (CO)
&apos;&apos;&apos; Return:
&apos;&apos;&apos; The local time converted from the corresponding UTC date and time as a Date
&apos;&apos;&apos; If the returned value is before 1900, it is likely that the Locale is not recognized
&apos;&apos;&apos; If the returned value matches the local time, it is likely that the timezone is not recognized
&apos;&apos;&apos; Examples:
&apos;&apos;&apos; regio.LocalDateTime(DateSerial(2022, 3, 20) + TimeSerial(16, 58, 17), &quot;Europe/Brussels&quot;, &quot;fr-BE&quot;)
&apos;&apos;&apos; &apos; 2022-03-20 17:58:17
Dim dLocalDateTime As Double &apos; Return value
Dim oLocale As Object &apos; com.sun.star.lang.Locale
Dim oCalendarImpl As Object &apos; com.sun.star.i18n.CalendarImpl
Const cstThisSub = &quot;Region.LocalDateTime&quot;
Const cstSubArgs = &quot;UTCDateTime, TimeZone, [Locale=&quot;&quot;&quot;&quot;]&quot;
If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
dLocalDateTime = -1
Check:
If IsMissing(Locale) Or IsEmpty(Locale) Then Locale = &quot;&quot;
If SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
If Not SF_Utils._Validate(LocalDateTime, &quot;LocalDateTime&quot;, V_DATE) Then GoTo Finally
If Not SF_Utils._Validate(TimeZone, &quot;TimeZone&quot;, V_STRING) Then GoTo Finally
If Not SF_Utils._Validate(Locale, &quot;Locale&quot;, V_STRING) Then GoTo Finally
End If
Set oLocale = SF_Region._GetLocale(Locale, pbCountry := True)
If IsNull(oLocale) Then GoTo Finally
Try:
Set oCalendarImpl = SF_Utils._GetUNOService(&quot;CalendarImpl&quot;)
With oCalendarImpl
.loadDefaultCalendarTZ(oLocale, TimeZone)
.setDateTime(UTCDateTime)
dLocalDateTime = .getLocalDateTime()
End With
Finally:
LocalDateTime = CDate(dLocalDateTime)
SF_Utils._ExitFunction(cstThisSub)
Exit Function
Catch:
GoTo Finally
End Function &apos; ScriptForge.SF_Region.LocalDateTime
REM -----------------------------------------------------------------------------
Public Function Methods() As Variant
&apos;&apos;&apos; Return the list of public methods of the Region class as an array
Methods = Array( _
&quot;DSTOffset&quot; _
, &quot;LocalDateTime&quot; _
, &quot;Number2Text&quot; _
, &quot;TimeZoneOffset&quot; _
, &quot;UTCDateTime&quot; _
, &quot;UTCNow&quot; _
)
End Function &apos; ScriptForge.SF_Region.Methods
REM -----------------------------------------------------------------------------
Public Function Number2Text(Optional ByVal Number As Variant _
, Optional ByVal Locale As Variant _
) As String
&apos;&apos;&apos; Convert numbers and money amounts in many languages into words
&apos;&apos;&apos; Args
&apos;&apos;&apos; Number: the number to spell out
&apos;&apos;&apos; Accepted types: strings or numeric values (integer or real numbers)
&apos;&apos;&apos; When a string, a variety of prefixes is supported
&apos;&apos;&apos; The string &quot;help&quot; provides helpful tips about allowed prefixes by language
&apos;&apos;&apos; Example for french
&apos;&apos;&apos; un, deux, trois
&apos;&apos;&apos; feminine: une, deux, trois
&apos;&apos;&apos; masculine: un, deux, trois
&apos;&apos;&apos; ordinal: premier, deuxième, troisième
&apos;&apos;&apos; ordinal-feminine: première, deuxième, troisième
&apos;&apos;&apos; ordinal-masculine: premier, deuxième, troisième
&apos;&apos;&apos; informal: onze-cents, douze-cents, treize-cents
&apos;&apos;&apos; Numbers may be prefixed by ISO currency codes (EUR, USD, ...)
&apos;&apos;&apos; Locale: expressed as a locale combining language-COUNTRY (la-CO), or language alone (la)
&apos;&apos;&apos; The list of supported languages can be found on
&apos;&apos;&apos; https://api.libreoffice.org/docs/idl/ref/interfacecom_1_1sun_1_1star_1_1linguistic2_1_1XNumberText.html
&apos;&apos;&apos; Return:
&apos;&apos;&apos; The number or amount transformed in words
&apos;&apos;&apos; Examples:
&apos;&apos;&apos; regio.Number2Text(&quot;help&quot;, &quot;fr&quot;) &apos; See above
&apos;&apos;&apos; regio.Number2Text(&quot;79,93&quot;, &quot;fr-BE&quot;) &apos; septante-neuf virgule nonante-trois
&apos;&apos;&apos; regio.Number2Text(Pi(), &quot;pt-BR&quot;) &apos; três vírgula um quatro um cinco nove dois seis cinco três cinco oito nove sete nove
&apos;&apos;&apos; regio.Number2Text(&quot;EUR 1234.56&quot;, &quot;it&quot;) &apos; milleduecentotrentaquattro euro cinquantasei centesimi
Dim sNumber2Text As String &apos; Return value
Dim oLocale As Object &apos; com.sun.star.lang.Locale
Dim oNumber2Text As Object &apos; com.sun.star.linguistic2.NumberText
Const cstThisSub = &quot;Region.Number2Text&quot;
Const cstSubArgs = &quot;Number, [Locale=&quot;&quot;&quot;&quot;]&quot;
If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
sNumber2Text = &quot;&quot;
Check:
If IsMissing(Locale) Or IsEmpty(Locale) Then Locale = &quot;&quot;
If SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
If Not SF_Utils._Validate(Number, &quot;Number&quot;, Array(V_STRING, V_NUMERIC)) Then GoTo Finally
If Not SF_Utils._Validate(Locale, &quot;Locale&quot;, V_STRING) Then GoTo Finally
End If
Set oLocale = SF_Region._GetLocale(Locale, pbLanguage := True)
If IsNull(oLocale) Then GoTo Finally
Try:
Set oNumber2Text = SF_Utils._GetUNOService(&quot;Number2Text&quot;)
sNumber2Text = oNumber2Text.getNumberText(Number, oLocale)
Finally:
Number2Text = sNumber2Text
SF_Utils._ExitFunction(cstThisSub)
Exit Function
Catch:
GoTo Finally
End Function &apos; ScriptForge.SF_Region.Number2Text
REM -----------------------------------------------------------------------------
Public Function Properties() As Variant
&apos;&apos;&apos; Return the list or properties of the Region class as an array
Properties = Array( _
&quot;Country&quot; _
, &quot;Currency&quot; _
, &quot;DatePatterns&quot; _
, &quot;DateSeparator&quot; _
, &quot;DayAbbrevNames&quot; _
, &quot;DayNames&quot; _
, &quot;DayNarrowNames&quot; _
, &quot;DecimalPoint&quot; _
, &quot;Language&quot; _
, &quot;ListSeparator&quot; _
, &quot;MonthAbbrevNames&quot; _
, &quot;MonthNames&quot; _
, &quot;MonthNarrowNames&quot; _
, &quot;ThousandSeparator&quot; _
, &quot;TimeSeparator&quot; _
)
End Function &apos; ScriptForge.SF_Region.Properties
REM -----------------------------------------------------------------------------
Public Function TimeZoneOffset(Optional ByVal TimeZone As Variant _
, Optional ByVal Locale As Variant _
) As Integer
&apos;&apos;&apos; Computes the offset between GMT and the given timezone and locale
&apos;&apos;&apos; Args
&apos;&apos;&apos; TimeZone: specified as &quot;Region/City&quot; name like &quot;Europe/Berlin&quot;, or a custom time zone ID such as &quot;UTC&quot; or &quot;GMT-8:00&quot;
&apos;&apos;&apos; Locale: expressed as a locale combining language-COUNTRY (la-CO), or COUNTRY alone (CO)
&apos;&apos;&apos; Return:
&apos;&apos;&apos; The offset in minutes
&apos;&apos;&apos; Examples:
&apos;&apos;&apos; regio.TimeZoneOffset(&quot;Europe/Brussels&quot;, &quot;fr-BE&quot;) &apos; 60
Dim iTimeZoneOffset As Integer &apos; Return value
Dim oLocale As Object &apos; com.sun.star.lang.Locale
Dim oCalendarImpl As Object &apos; com.sun.star.i18n.CalendarImpl
Const cstThisSub = &quot;Region.TimeZoneOffset&quot;
Const cstSubArgs = &quot;TimeZone, [Locale=&quot;&quot;&quot;&quot;]&quot;
If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
iTimeZoneOffset = 0
Check:
If IsMissing(Locale) Or IsEmpty(Locale) Then Locale = &quot;&quot;
If SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
If Not SF_Utils._Validate(TimeZone, &quot;TimeZone&quot;, V_STRING) Then GoTo Finally
If Not SF_Utils._Validate(Locale, &quot;Locale&quot;, V_STRING) Then GoTo Finally
End If
Set oLocale = SF_Region._GetLocale(Locale, pbCountry := True)
If IsNull(oLocale) Then GoTo Finally
Try:
Set oCalendarImpl = SF_Utils._GetUNOService(&quot;CalendarImpl&quot;)
With oCalendarImpl
.loadDefaultCalendarTZ(oLocale, TimeZone)
iTimeZoneOffset = .getValue(com.sun.star.i18n.CalendarFieldIndex.ZONE_OFFSET)
End With
Finally:
TimeZoneOffset = iTimeZoneOffset
SF_Utils._ExitFunction(cstThisSub)
Exit Function
Catch:
GoTo Finally
End Function &apos; ScriptForge.SF_Region.TimeZoneOffset
REM -----------------------------------------------------------------------------
Public Function UTCDateTime(Optional ByVal LocalDateTime As Variant _
, Optional ByVal TimeZone As Variant _
, Optional ByVal Locale As Variant _
) As Date
&apos;&apos;&apos; Computes the UTC date and time of a given local date and time
&apos;&apos;&apos; Args
&apos;&apos;&apos; LocalDateTime: the date and time measured in a given timezone
&apos;&apos;&apos; TimeZone: specified as &quot;Region/City&quot; name like &quot;Europe/Berlin&quot;, or a custom time zone ID such as &quot;UTC&quot; or &quot;GMT-8:00&quot;
&apos;&apos;&apos; Locale: expressed as a locale combining language-COUNTRY (la-CO), or COUNTRY alone (CO)
&apos;&apos;&apos; Return:
&apos;&apos;&apos; The local time converted to the corresponding UTC date and time as a Date
&apos;&apos;&apos; If the returned value is before 1900, it is likely that the Locale is not recognized
&apos;&apos;&apos; If the returned value matches the local time, it is likely that the timezone is not recognized
&apos;&apos;&apos; Examples:
&apos;&apos;&apos; regio.UTCDateTime(DateSerial(2022, 3, 20) + TimeSerial(17, 58, 17), &quot;Europe/Brussels&quot;, &quot;fr-BE&quot;)
&apos;&apos;&apos; &apos; 2022-03-20 16:58:17
Dim dUTCDateTime As Double &apos; Return value
Dim oLocale As Object &apos; com.sun.star.lang.Locale
Dim oCalendarImpl As Object &apos; com.sun.star.i18n.CalendarImpl
Const cstThisSub = &quot;Region.UTCDateTime&quot;
Const cstSubArgs = &quot;LocalDateTime, TimeZone, [Locale=&quot;&quot;&quot;&quot;]&quot;
If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
dUTCDateTime = -1
Check:
If IsMissing(Locale) Or IsEmpty(Locale) Then Locale = &quot;&quot;
If SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
If Not SF_Utils._Validate(LocalDateTime, &quot;LocalDateTime&quot;, V_DATE) Then GoTo Finally
If Not SF_Utils._Validate(TimeZone, &quot;TimeZone&quot;, V_STRING) Then GoTo Finally
If Not SF_Utils._Validate(Locale, &quot;Locale&quot;, V_STRING) Then GoTo Finally
End If
Set oLocale = SF_Region._GetLocale(Locale, pbCountry := True)
If IsNull(oLocale) Then GoTo Finally
Try:
Set oCalendarImpl = SF_Utils._GetUNOService(&quot;CalendarImpl&quot;)
With oCalendarImpl
.loadDefaultCalendarTZ(oLocale, TimeZone)
.setLocalDateTime(LocalDateTime)
dUTCDateTime = .getDateTime()
End With
Finally:
UTCDateTime = CDate(dUTCDateTime)
SF_Utils._ExitFunction(cstThisSub)
Exit Function
Catch:
GoTo Finally
End Function &apos; ScriptForge.SF_Region.UTCDateTime
REM -----------------------------------------------------------------------------
Public Function UTCNow(Optional ByVal TimeZone As Variant _
, Optional ByVal Locale As Variant _
) As Date
&apos;&apos;&apos; Computes the actual UTC date and time
&apos;&apos;&apos; Args
&apos;&apos;&apos; TimeZone: specified as &quot;Region/City&quot; name like &quot;Europe/Berlin&quot;, or a custom time zone ID such as &quot;UTC&quot; or &quot;GMT-8:00&quot;
&apos;&apos;&apos; Locale: expressed as a locale combining language-COUNTRY (la-CO), or COUNTRY alone (CO)
&apos;&apos;&apos; Return:
&apos;&apos;&apos; The actual UTC date and time as a Date
&apos;&apos;&apos; If the returned value is before 1900, it is likely that the Locale is not recognized
&apos;&apos;&apos; If the returned value matches the local time, it is likely that the timezone is not recognized
&apos;&apos;&apos; Examples:
&apos;&apos;&apos; regio.UTCNow(&quot;Europe/Brussels&quot;, &quot;fr-BE&quot;) &apos; 2022-03-20 16:58:17
Dim dUTCNow As Double &apos; Return value
Dim oLocale As Object &apos; com.sun.star.lang.Locale
Dim oCalendarImpl As Object &apos; com.sun.star.i18n.CalendarImpl
Const cstThisSub = &quot;Region.UTCNow&quot;
Const cstSubArgs = &quot;TimeZone, [Locale=&quot;&quot;&quot;&quot;]&quot;
If SF_Utils._ErrorHandling() Then On Local Error GoTo Catch
dUTCNow = -1
Check:
If IsMissing(Locale) Or IsEmpty(Locale) Then Locale = &quot;&quot;
If SF_Utils._EnterFunction(cstThisSub, cstSubArgs) Then
If Not SF_Utils._Validate(TimeZone, &quot;TimeZone&quot;, V_STRING) Then GoTo Finally
If Not SF_Utils._Validate(Locale, &quot;Locale&quot;, V_STRING) Then GoTo Finally
End If
Set oLocale = SF_Region._GetLocale(Locale, pbCountry := True)
If IsNull(oLocale) Then GoTo Finally
Try:
Set oCalendarImpl = SF_Utils._GetUNOService(&quot;CalendarImpl&quot;)
With oCalendarImpl
.loadDefaultCalendarTZ(oLocale, TimeZone)
.setLocalDateTime(Now())
dUTCNow = .getDateTime()
End With
Finally:
UTCNow = CDate(dUTCNow)
SF_Utils._ExitFunction(cstThisSub)
Exit Function
Catch:
GoTo Finally
End Function &apos; ScriptForge.SF_Region.UTCNow
REM =========================================================== PRIVATE FUNCTIONS
REM -----------------------------------------------------------------------------
Private Function _GetLocale(ByVal psLocale As String _
, Optional ByVal pbCountry As Variant _
, Optional ByVal pbLanguage As Variant _
) As Object
&apos;&apos;&apos; Convert a locale given as a string to a com.sun.star.lang.Locale object
&apos;&apos;&apos; Args:
&apos;&apos;&apos; psLocale: the input string, as &quot;la-CO&quot;, &quot;la&quot; or &quot;CO&quot;
&apos;&apos;&apos; pbCountry: True when &quot;CO&quot; only is admitted
&apos;&apos;&apos; pbLanguage: True when &quot;la&quot; only is admitted
&apos;&apos;&apos; At most one out of pbLanguage or pbCountry may be True
&apos;&apos;&apos; Returns:
&apos;&apos;&apos; com.sun.star.lang.Locale
Dim sLocale As String &apos; &quot;la-CO&quot;
Dim iLocale As Integer &apos; Index in reference tables
Dim oLocale As Object &apos; Return value com.sun.star.lang.Locale
Dim i As Integer
If IsMissing(pbCountry) Or IsEmpty(pbCountry) Then pbCountry = False
If IsMissing(pbLanguage) Or IsEmpty(pbLanguage) Then pbLanguage = False
_LoadAllLocales() &apos; Initialize locale reference tables
Check:
&apos; The argument may be a language &quot;la&quot;, a country &quot;CO&quot; or a Locale &quot;la-CO&quot;
&apos; Scan the reference tables to find a valid locale as a com.sun.star.lang.Locale
Set oLocale = Nothing : sLocale = &quot;&quot; : iLocale = -1
If Len(psLocale) = 0 Then &apos; Default value is the office com.sun.star.i18n.Locale
sLocale = UserLocale
iLocale = UserIndex
ElseIf InStr(psLocale, &quot;-&quot;) = 0 Then &apos; Language only or country only
Select Case True
Case pbLanguage
&apos; Find any locale having the argument as language
For i = 0 To UBound(LocaleNames)
&apos; A language is presumed 2 or 3 characters long
If Split(LocaleNames(i), &quot;-&quot;)(0) = LCase(psLocale) Then
sLocale = LocaleNames(i)
iLocale = i
Exit For
End If
Next i
Case pbCountry
&apos; Find any locale having the argument as country
For i = 0 To UBound(LocaleNames)
&apos; A country is presumed exactly 2 characters long
If Right(LocaleNames(i), 2) = UCase(psLocale) Then
sLocale = LocaleNames(i)
iLocale = i
Exit For
End If
Next i
Case Else
End Select
Else &apos; A full locale is given
iLocale = SF_Array.IndexOf(LocaleNames, psLocale, CaseSensitive := False)
If iLocale &gt;= 0 Then sLocale = LocaleNames(iLocale)
End If
Try:
&apos; Build error message when relevant
If iLocale &lt; 0 Then
If Not SF_Utils._Validate(psLocale, &quot;Locale&quot;, V_STRING, LocaleNames) Then GoTo Finally
Else
Set oLocale = CreateUnoStruct(&quot;com.sun.star.lang.Locale&quot;)
oLocale.Language = Split(sLocale, &quot;-&quot;)(0) &apos; A language is 2 or 3 characters long
oLocale.Country = Right(sLocale, 2)
End If
Finally:
Set _GetLocale = oLocale
Exit Function
End Function &apos; ScriptForge.SF_Region._GetLocale
REM -----------------------------------------------------------------------------
Private Sub _LoadAllLocales()
&apos;&apos;&apos; Initialize the LocaleNames array = the list of all available locales in the LibreOffice installation
Dim oOffice As Object &apos; com.sun.star.lang.Locale
Dim vLocales As Variant &apos; Array of com.sun.star.lang.Locale
Dim iTop As Integer &apos; Upper bound of LocaleNames
Dim i As Integer
Try:
&apos; Office locale
If Len(UserLocale) = 0 Then
Set oOffice = SF_Utils._GetUNOService(&quot;OfficeLocale&quot;)
UserLocale = oOffice.Language &amp; &quot;-&quot; &amp; oOffice.Country
End If
&apos; LocaleData, localeNames and UserIndex
If IsEmpty(LocaleData) Or IsNull(LocaleData) Or Not IsArray(LocaleNames) Then
LocaleData = SF_Utils._GetUNOService(&quot;LocaleData&quot;)
vLocales = LocaleData.getAllInstalledLocaleNames()
LocaleNames = Array()
iTop = UBound(vLocales)
ReDim LocaleNames(0 To iTop)
For i = 0 To iTop
LocaleNames(i) = vLocales(i).Language &amp; &quot;-&quot; &amp; vLocales(i).Country
If LocaleNames(i) = UserLocale Then UserIndex = i
Next i
End If
End Sub &apos; ScriptForge.SF_Region._LoadAllLocales
REM -----------------------------------------------------------------------------
Private Function _PropertyGet(Optional ByVal psProperty As String _
, Optional ByVal pvLocale As Variant) As Variant
&apos;&apos;&apos; Return the value of the named property
&apos;&apos;&apos; Args:
&apos;&apos;&apos; psProperty: the name of the property
&apos;&apos;&apos; pvLocale: a locale in the form language-COUNTRY (la-CO) or language only, or country only
&apos;&apos;&apos; When language or country only, any locale matching either the language or the country is selected
Dim oLocale As Object &apos; com.sun.star.lang.Locale
Dim vCurrencies As Variant &apos; Array of com.sun.star.i18n.Currency
Dim oCurrency As Object &apos; com.sun.star.i18n.Currency
Dim oLanguageCountryInfo As Object &apos; com.sun.star.i18n.LanguageCountryInfo
Dim oLocaleDataItem2 As Object &apos; com.sun.star.i18n.LocaleDataItem2
Dim oCalendarImpl As Object &apos; com.sun.star.i18n.CalendarImpl
Dim oCalItem As Object &apos; com.sun.star.i18n.CalendarItem2
Dim vCalItems() As Variant &apos; Array of days/months
Dim i As Integer, j As Integer
Dim cstThisSub As String
Const cstSubArgs = &quot;&quot;
cstThisSub = &quot;Region.Get&quot; &amp; psProperty
SF_Utils._EnterFunction(cstThisSub, cstSubArgs)
Check:
If IsMissing(pvLocale) Or IsEmpty(pvLocale) Then pvLocale = &quot;&quot;
If Not SF_Utils._Validate(pvLocale, &quot;Locale&quot;, V_STRING) Then GoTo Finally
Select Case psProperty
Case &quot;Currency&quot;, &quot;Country&quot;
Set oLocale = SF_Region._GetLocale(pvLocale, pbCountry := True) &apos; Country only is admitted
Case &quot;Language&quot;, &quot;DayNames&quot;, &quot;DayAbbrevNames&quot;, &quot;DayNarrowNames&quot; _
, &quot;MonthNames&quot;, &quot;MonthAbbrevNames&quot;, &quot;MonthNarrowNames&quot;
Set oLocale = SF_Region._GetLocale(pvLocale, pbLanguage := True) &apos; Language only is admitted
Case Else
Set oLocale = SF_Region._GetLocale(pvLocale)
End Select
If IsNull(oLocale) Then GoTo Finally
Try:
Select Case psProperty
Case &quot;Country&quot;, &quot;Language&quot;
Set oLanguageCountryInfo = LocaleData.getLanguageCountryInfo(oLocale)
With oLanguageCountryInfo
If psProperty = &quot;Country&quot; Then _PropertyGet = .CountryDefaultName Else _PropertyGet = .LanguageDefaultName
End With
Case &quot;Currency&quot;
vCurrencies = LocaleData.getAllCurrencies(oLocale)
_PropertyGet = &quot;&quot;
For Each oCurrency In vCurrencies
If oCurrency.Default Then
_PropertyGet = oCurrency.BankSymbol
Exit For
End If
Next oCurrency
Case &quot;DatePatterns&quot;
_PropertyGet = LocaleData.getDateAcceptancePatterns(oLocale)
Case &quot;DateSeparator&quot;, &quot;DecimalPoint&quot;, &quot;ListSeparator&quot;, &quot;ThousandSeparator&quot;, &quot;TimeSeparator&quot;
Set oLocaleDataItem2 = LocaleData.getLocaleItem2(oLocale)
With oLocaleDataItem2
Select Case psProperty
Case &quot;DateSeparator&quot; : _PropertyGet = .dateSeparator
Case &quot;DecimalPoint&quot; : _PropertyGet = .decimalSeparator
Case &quot;ListSeparator&quot; : _PropertyGet = .listSeparator
Case &quot;ThousandSeparator&quot; : _PropertyGet = .thousandSeparator
Case &quot;TimeSeparator&quot; : _PropertyGet = .timeSeparator
End Select
End With
Case &quot;DayAbbrevNames&quot;, &quot;DayNames&quot;, &quot;DayNarrowNames&quot;
Set oCalendarImpl = SF_Utils._GetUNOService(&quot;CalendarImpl&quot;)
With oCalendarImpl
.loadDefaultCalendar(oLocale)
vCalItems = Array() : ReDim vCalItems(0 To 6)
For i = 0 To UBound(.Days2)
Set oCalItem = .Days2(i)
j = Iif(i = 0, 6, i - 1)
Select Case psProperty
Case &quot;DayNames&quot; : vCalItems(j) = oCalItem.FullName
Case &quot;DayAbbrevNames&quot; : vCalItems(j) = oCalItem.AbbrevName
Case &quot;DayNarrowNames&quot; : vCalItems(j) = oCalItem.NarrowName
End Select
Next i
_PropertyGet = vCalItems
End With
Case &quot;MonthAbbrevNames&quot;, &quot;MonthNames&quot;, &quot;MonthNarrowNames&quot;
Set oCalendarImpl = SF_Utils._GetUNOService(&quot;CalendarImpl&quot;)
With oCalendarImpl
.loadDefaultCalendar(oLocale)
vCalItems = Array() : ReDim vCalItems(0 To 11)
For i = 0 To UBound(.Months2)
Set oCalItem = .Months2(i)
Select Case psProperty
Case &quot;MonthNames&quot; : vCalItems(i) = oCalItem.FullName
Case &quot;MonthAbbrevNames&quot; : vCalItems(i) = oCalItem.AbbrevName
Case &quot;MonthNarrowNames&quot; : vCalItems(i) = oCalItem.NarrowName
End Select
Next i
_PropertyGet = vCalItems
End With
Case Else
_PropertyGet = &quot;&quot;
End Select
Finally:
SF_Utils._ExitFunction(cstThisSub)
Exit Function
End Function &apos; ScriptForge.SF_Region._PropertyGet
REM ================================================ END OF SCRIPTFORGE.SF_REGION
</script:module>