Tekst informacyjny o polityce Cookies Close   
    
 
         
• 1. Strona główna
• 2. Kontakt: e-Mail
 
         
• 1. Baza danych
• 2. Tabele i kwerendy
• 3. Formularze
• 4. Raporty
• 5. Moduły i makra
• 6. Obsługa błędów
 
    

II.   VBA 

    
• 1. Okna Accessa
• 2. Okna Formularzy
• 3.Okna Dialogowe
• 4. Tekst
• 5. Liczby
• 6. Pliki
• 7. Inne
 
    

III.   API 

    
• 1. Ogólnie o API
• 2. Funkcje API
• 3. System
• 4. Praca z oknami
• 5. Okna dialogowe
• 6. API - Inne
 
         
• 1. Bitmapy 24 Bit
• 2. GDI i HDC
• 3. Kody kreskowe
• 4. Formant Image
• 5. FreeImage.dll
 
    

V.   Inne 

    
• 1. Shell i MsDOS
• 2. Kontrolki
• 3. ६ԼҚ ਸ
• 4. Unikod

 
Odwiedzin:

Logo AccessFAQ• II.5. VBA - Operacje na liczbach [2] •

5.10 Jak zamienić liczbę typu Long na postać dwójkową za pomocą kodu VBA oraz jak to zrobić za pomocą kwerendy (bez użycia funkcji zewnętrznych) ?
5.11 Jak przyspieszyć od 2 do 12 razy kopiowanie tablicy zawierającej dane liczbowe ?
5.12 Jak przyspieszyć od 3 do 15 razy wstawianie tablicy do tablicy z danymi liczbowymi ?
5.13 Jak przekonwertować czas uniwersalny UTC na czas lokalny i odwrotnie ?
5.14 Jak pobrać separator daty, format daty krótkiej, ilość dni w miesiącu, nazwy miesięcy, nazwy dni tygodnia, pierwszy pełny tydzień w roku ?
<<• idź do str. 1 •>>
 

5.10 Jak zamienić liczbę typu Long na postać dwójkową za pomocą kodu VBA oraz jak to zrobić za pomocą kwerendy (bez użycia funkcji zewnętrznych) ?



•  Metoda I - Za pomocą kodu VBA

Private Declare Sub CopyMemory Lib "kernel32" _
Alias "RtlMoveMemory" _
(Destination As Any, _
Source As Any, _
ByVal Length As Long)


' funkcja konwertuje liczbę na postać dwójkową (ciąg znaków "0" lub "1") określających stan poszczególnych bitów liczby
Public Function zbLongToBin(lNumber As Long) As String
Dim aAsc01(0 To 31) As Byte
Static aExp(0 To 31) As Long
Static sZeroString As String
Dim i As Long
Const MY_ASC_1 As Long = 49

' jednorazowo (przy pierwszym wywołaniu funkcji) zapełnij tablicę aExp() i ustaw zmienną sZeroString (obie typu Static),

If Len(sZeroString) = 0 Then
sZeroString = String(32, "0")
' zapełnij tablicę wartościami potęg liczby 2
For i = 0 To 30
aExp(i) = (2 ^ i)
Next
End If

' resetuj tablicę aAsc01 wartościami Asc("0")
CopyMemory aAsc01(0), ByVal sZeroString, 32

For i = 30 To 0 Step -1
' dla ustawionych bitów, zmień wartość elementu
' tablicy na wartość Asc("1")

If (lNumber And aExp(i)) > 0 Then
aAsc01(31 - i) = MY_ASC_1
End If
Next

' dla liczb ujemnych ustaw wartość elementu tablicy
' określający bit znaku na Asc("1")

If lNumber < 0 Then aAsc01(0) = MY_ASC_1

zbLongToBin = StrConv(aAsc01(), vbUnicode)

End Function


' funkcja konwertuje postać dwójkową liczby (ciąg znaków "0" i "1") na liczbę
Public Function zbBinToLong(sBinString As String) As Long
Dim aBits(0 To 31) As Byte
Dim sBaseString As String
Dim i As Long
Const MY_ASC_0 As Long = 48
Const MY_ASC_1 As Long = 49

If Len(sBinString) = 0 Or Len(sBinString) > 32 Then Exit Function

sBaseString = String(32, "0")
' wpisz do ciągu bazowego wejściowy ciąg bitów liczby
Mid$(sBaseString, 32 - Len(sBinString) + 1) = sBinString

CopyMemory aBits(0), ByVal sBaseString, Len(sBaseString)

For i = 1 To 31
Select Case aBits(i)
' dopuszczalne tylko Asc("0") lub Asc("1")
Case MY_ASC_0, MY_ASC_1
zbBinToLong = 2 * zbBinToLong + (aBits(i) - MY_ASC_0)
Case Else
' niedozwolony znak, zeruj funkcję
zbBinToLong = 0
Exit Function
End Select
Next

' jeżeli liczba ujemna, to ustaw bit znaku na 1
If aBits(0) = MY_ASC_1 Then
zbBinToLong = zbBinToLong Or &H80000000
End If

End Function

                



•  Metoda II - Za pomocą kwerendy
grupa: pl.comp.bazy-danych.msaccess
w oparciu o wątek: Zamiana liczby DEC na Bit



SELECT
tNumbers.tValue,
[tValue]<0 AS tSign,
IIf([tSign]<0,[tValue]+1,[tValue]) AS MyValue,
IIf([tSign]<0,([MyValue]\2^0 Mod 2) +1, ([MyValue]\2^0 Mod 2)) AS B0,
IIf([tSign]<0,([MyValue]\2^1 Mod 2) +1, ([MyValue]\2^1 Mod 2)) AS B1,
IIf([tSign]<0,([MyValue]\2^2 Mod 2) +1, ([MyValue]\2^2 Mod 2)) AS B2,
IIf([tSign]<0,([MyValue]\2^3 Mod 2) +1, ([MyValue]\2^3 Mod 2)) AS B3,
IIf([tSign]<0,([MyValue]\2^4 Mod 2) +1, ([MyValue]\2^4 Mod 2)) AS B4,
IIf([tSign]<0,([MyValue]\2^5 Mod 2) +1, ([MyValue]\2^5 Mod 2)) AS B5,
IIf([tSign]<0,([MyValue]\2^6 Mod 2) +1, ([MyValue]\2^6 Mod 2)) AS B6,
IIf([tSign]<0,([MyValue]\2^7 Mod 2) +1, ([MyValue]\2^7 Mod 2)) AS B7,
IIf([tSign]<0,([MyValue]\2^8 Mod 2) +1, ([MyValue]\2^8 Mod 2)) AS B8,
IIf([tSign]<0,([MyValue]\2^9 Mod 2) +1, ([MyValue]\2^9 Mod 2)) AS B9,
IIf([tSign]<0,([MyValue]\2^10 Mod 2) +1, ([MyValue]\2^10 Mod 2)) AS B10,
IIf([tSign]<0,([MyValue]\2^11 Mod 2) +1, ([MyValue]\2^11 Mod 2)) AS B11,
IIf([tSign]<0,([MyValue]\2^12 Mod 2) +1, ([MyValue]\2^12 Mod 2)) AS B12,
IIf([tSign]<0,([MyValue]\2^13 Mod 2) +1, ([MyValue]\2^13 Mod 2)) AS B13,
IIf([tSign]<0,([MyValue]\2^14 Mod 2) +1, ([MyValue]\2^14 Mod 2)) AS B14,
IIf([tSign]<0,([MyValue]\2^15 Mod 2) +1, ([MyValue]\2^15 Mod 2)) AS B15,
IIf([tSign]<0,([MyValue]\2^16 Mod 2) +1, ([MyValue]\2^16 Mod 2)) AS B16,
IIf([tSign]<0,([MyValue]\2^17 Mod 2) +1, ([MyValue]\2^17 Mod 2)) AS B17,
IIf([tSign]<0,([MyValue]\2^18 Mod 2) +1, ([MyValue]\2^18 Mod 2)) AS B18,
IIf([tSign]<0,([MyValue]\2^19 Mod 2) +1, ([MyValue]\2^19 Mod 2)) AS B19,
IIf([tSign]<0,([MyValue]\2^20 Mod 2) +1, ([MyValue]\2^20 Mod 2)) AS B20,
IIf([tSign]<0,([MyValue]\2^21 Mod 2) +1, ([MyValue]\2^21 Mod 2)) AS B21,
IIf([tSign]<0,([MyValue]\2^22 Mod 2) +1, ([MyValue]\2^22 Mod 2)) AS B22,
IIf([tSign]<0,([MyValue]\2^23 Mod 2) +1, ([MyValue]\2^23 Mod 2)) AS B23,
IIf([tSign]<0,([MyValue]\2^24 Mod 2) +1, ([MyValue]\2^24 Mod 2)) AS B24,
IIf([tSign]<0,([MyValue]\2^25 Mod 2) +1, ([MyValue]\2^25 Mod 2)) AS B25,
IIf([tSign]<0,([MyValue]\2^26 Mod 2) +1, ([MyValue]\2^26 Mod 2)) AS B26,
IIf([tSign]<0,([MyValue]\2^27 Mod 2) +1, ([MyValue]\2^27 Mod 2)) AS B27,
IIf([tSign]<0,([MyValue]\2^28 Mod 2) +1, ([MyValue]\2^28 Mod 2)) AS B28,
IIf([tSign]<0,([MyValue]\2^29 Mod 2) +1, ([MyValue]\2^29 Mod 2)) AS B29,
IIf([tSign]<0,([MyValue]\2^30 Mod 2) +1, ([MyValue]\2^30 Mod 2)) AS B30,
IIf([tValue]<0,1,0) AS B31,
[B31] & [B30] & [B29] & [B28] & [B27] & [B26] & [B25] & [B24] &
[B23] & [B22] & [B21] & [B20] & [B19] & [B18] & [B17] & [B16] &
[B15] & [B14] & [B13] & [B12] & [B11] & [B10] & [B9] & [B8] &
[B7] & [B6] & [B5] & [B4] & [B3] & [B2] & [B1] & [B0] AS BitString
FROM tNumbers;


   Przykład:  • vba14b_10  •  34 KB  •  status: FREE  Pobrano    razy   


 ΔΔΔ 

 

5.11 Jak przyspieszyć od 2 do 12 razy kopiowanie tablicy zawierającej dane liczbowe ?

' Kopię tablicy każdego typu możemy wykonać przechodząc w pętli For Next po wszystkich elementach tablicy wejściowej i skopiować te elementy do tablicy docelowej, którą następnie zwrócimy ByRef w arumencie arrRet().
' Funkcja przy powodzeniu zwraca ilość elementów tablicy, przy niepowodzeniu Zero


Public Function zbCopyArrayForNext(arrIn() As Long, arrRet() As Long) As Long
Dim i As Long

' sprawdź, czy tablica jest zainicjowana
On Error Resume Next
i = UBound(arrIn)
If Err.Number <> 0 Then
Err.Clear
Exit Function
End If
On Error GoTo 0

ReDim arrRet(LBound(arrIn) To UBound(arrIn))

For i = LBound(arrIn) To UBound(arrIn)
arrRet(i) = arrIn(i)
Next

zbCopyArrayForNext = (UBound(arrRet) - LBound(arrRet) + 1)

End Function

' jeżeli chcemy przyspieszyć kopiowanie tablic, ale tylko tablic zawierających dane numeryczne, musimy proces ten częściowo wykonać bezpośrednio na blokach w pamięci, do czego potrzebne będą poniższe funkcje API:


Private Declare Sub CopyMemory Lib "kernel32" _
Alias "RtlMoveMemory" _
(Destination As Any, _
Source As Any, _
ByVal Length As Long)
Private Declare Function GlobalAlloc Lib "kernel32" _
(ByVal wFlags As Long, _
ByVal dwBytes As Long) As Long
Private Declare Function GlobalLock Lib "kernel32" _
(ByVal hMem As Long) As Long
Private Declare Function GlobalUnlock Lib "kernel32" _
(ByVal hMem As Long) As Long
Private Declare Function GlobalFree Lib "kernel32" _
(ByVal hMem As Long) As Long
Private Const GMEM_MOVEABLE = &H2
Private Const GMEM_ZEROINIT = &H40



' tworzy kopię tablicy wejściowej, którą zwraca ByRef w arumencie arrRet(), przy powodzeniu zwraca ilość elementów tablicy, w przeciwnym razie Zero
Public Function zbCopyArrayInMem( _
arrIn() As Long, _
arrRet() As Long) As Long
Dim hMem As Long' uchwyt bloku pamięci
Dim pMem As Long' wskaźnik do bloku pamięci
Dim lSizeArrIn As Long' ilość elementów w tablicy bazowej
Dim lVarSize As Long' długość w bajtach elementu tablicy
Dim lLenData As Long' długość w bajtach danych w tablicy

' sprawdź, czy tablica jest zainicjowana
On Error Resume Next
    lSizeArrIn = (UBound(arrIn) - LBound(arrIn) + 1)
    If Err.Number <> 0 Then
        Err.Clear
        Exit Function
    End If
On Error GoTo 0

Select Case VarType(arrIn(LBound(arrIn)))
    Case vbByte
        lVarSize = 1
    Case vbInteger, vbBoolean
        lVarSize = 2
    Case vbLong, vbSingle
        lVarSize = 4
    Case vbDouble, vbCurrency, vbDate
        lVarSize = 8
    Case Else
        Exit Function
End Select

lLenData = lSizeArrIn * lVarSize
' alokuj blok w pamięci i pobierz jego uchwyt
hMem = GlobalAlloc(GMEM_MOVEABLE, lLenData)
' zablokuj blok pamięci i pobierz wskaźnik do pierwszego bajta
pMem = GlobalLock(hMem)

' ustaw rozmiar tablicy zwracanej
ReDim arrRet(LBound(arrIn) To UBound(arrIn))
' kopiuj tablicę do bloku pamięci
CopyMemory ByVal pMem, arrIn(LBound(arrIn)), lLenData
' kopiuj zawartość bloku pamięci do tablicy arrRet()
CopyMemory arrRet(LBound(arrIn)), ByVal pMem, lLenData

Call GlobalUnlock(hMem)
Call GlobalFree(hMem)

If (UBound(arrRet) - LBound(arrRet) + 1) = lSizeArrIn Then
    zbCopyArrayInMem = lSizeArrIn
End If

End Function

Porównanie szybkości obu funkcji dla tablicy 1 000 000 elementowej
Typ danychzbCopyArrayForNextzbCopyArrayInMemMet.I/Met.II
Byte426 ms 35 ms12,2
Integer447 ms 70 ms 6,4
Boolean448 ms 72 ms 6,2
Long496 ms145 ms 3,4
Single447 ms142 ms 3,1
Double562 ms283 ms 2,0
Date572 ms282 ms 2,0
Currency563 ms283 ms 2,0

• Jak widać szybkość funkcji zbCopyArrayForNext jest w niewielkim stopniu zależna od wielkości danych (426 ms dla 1 bajta i 560 ms dla 8 bajtów) o tyle szybkość funkcji zbCopyArrayInMem jest proporcjonalna do wielkości zmiennej. I tak dla 1 bajta 35 ms, dla 2 bajtów 70 ms, dla 4 bajtów 140 ms, a dla 8 bajtów 280 ms).



' w przypadku gdy musimy wykonać kopię tablicy typu Byte to możemy to zrobić jeszcze ok. 2x szybciej od zbCopyArrayInMem stosując bezpośrednie przypisanie
Public Function zbCopyArrayBytes( _
arrIn() As Byte, _
arrRet() As Byte) As Long
    On Error Resume Next
        ' nawet nie musimy ustawiać wymiarów tablicy
        arrRet() = arrIn()
        zbCopyArrayBytes = (UBound(arrRet) - LBound(arrRet) + 1)
    On Error GoTo 0
End Function

 ΔΔΔ 

 

5.12 Jak przyspieszyć od 3 do 15 razy wstawianie tablicy do tablicy z danymi liczbowymi ?

' przy powodzeniu zwraca ilość elementów tablicy arrRet zwracanej w argumencie ByRef, przy niepowodzeniu zwraca wartość mniejszą od 1;
' - 3 "niezainicjowane obie tablice" i niezainicjowaną tablicę arrRet,
' - 2 "niezainicjowana tablica arrInsert()" i tablicę arrRet będącą kopią tablicy arrBase(),
' - 1 "niezainicjowana tablica arrBase()" i tablicę arrRet będącą kopią tablicy arrInsert(),
'  0 "nieprzewidziany błąd" i nieokreślony stan tablicy arrRet,
' • arrBase() - tablica bazowa, do której będziemy wstawiali drugą tablicę
' • arrInsert() - tablica wstawiana do pierwszej tablicy
' • lBefore - nr elementu (nie Index) tablicy, przed którym ma być wstawiona tablica


Public Function zbArrayIntoArrayForNext( _
arrBase() As Long, arrInsert() As Long, _
arrRet() As Long, lBefore As Long) As Long
Dim lSizeArrBase As Long
Dim lSizeArrIns As Long
Dim i As Long
Dim j As Long

' sprawdź, czy tablice są zainicjowane
On Error Resume Next
lSizeArrBase = (UBound(arrBase) - LBound(arrBase) + 1)
lSizeArrIns = (UBound(arrInsert) - LBound(arrInsert) + 1)
On Error GoTo 0
' obie niezainicjowane
If lSizeArrBase = 0 And lSizeArrIns = 0 Then
zbArrayIntoArrayForNext = -3
Exit Function
End If
' pierwsza tablica niezainicjowana, zwróć drugą tablicę
If lSizeArrBase = 0 Then
Call zbCopyArrayForNext(arrInsert, arrRet)
zbArrayIntoArrayForNext = -1
Exit Function
End If
' druga tablica niezainicjowana, zwróć pierwszą tablicę
If lSizeArrIns = 0 Then
Call zbCopyArrayForNext(arrBase, arrRet)
zbArrayIntoArrayForNext = -2
Exit Function
End If

' sprawdź poprawność miejsca wprowadzania drugiej tablicy
If lBefore < 1 Then lBefore = 1
If lBefore > lSizeArrBase Then lBefore = lSizeArrBase + 1

ReDim arrRet(LBound(arrBase) To LBound(arrBase) + _
lSizeArrBase + lSizeArrIns - 1)
' I - kopiuj pierwszą część
For i = LBound(arrBase) To LBound(arrBase) + lBefore - 2
arrRet(i) = arrBase(i)
Next
' II - kopiuj całą tablicę wstawianą
For j = LBound(arrInsert) To UBound(arrInsert)
arrRet(i) = arrInsert(j)
i = i + 1
Next
' III - kopiuj końcową cześć tablicy bazowej
For j = LBound(arrBase) + lBefore - 1 To UBound(arrBase)
arrRet(i) = arrBase(j)
i = i + 1
Next

If (UBound(arrRet) - LBound(arrRet) + 1) = _
lSizeArrBase + lSizeArrIns Then
zbArrayIntoArrayForNext = lSizeArrBase + lSizeArrIns
Else
zbArrayIntoArrayForNext = 0
End If

End Function

' jeżeli chcemy przyspieszyć wstawianie tablicy do tablicy, ale tylko dla tablic zawierających dane numerycznę, musimy proces ten częściowo wykonać bezpośrednio na blokach w pamięci, do czego potrzebne będą poniższe funkcje API:


Private Declare Sub CopyMemory Lib "kernel32" _
Alias "RtlMoveMemory" _
(Destination As Any, _
Source As Any, _
ByVal Length As Long)
Private Declare Function GlobalAlloc Lib "kernel32" _
(ByVal wFlags As Long, _
ByVal dwBytes As Long) As Long
Private Declare Function GlobalLock Lib "kernel32" _
(ByVal hMem As Long) As Long
Private Declare Function GlobalUnlock Lib "kernel32" _
(ByVal hMem As Long) As Long
Private Declare Function GlobalFree Lib "kernel32" _
(ByVal hMem As Long) As Long
Private Const GMEM_MOVEABLE = &H2
Private Const GMEM_ZEROINIT = &H40



' przy powodzeniu zwraca ilość elementów tablicy arrRet zwracanej w argumencie ByRef
' przy niepowodzeniu zwraca wartość mniejszą od 1;
' - 4 "nieobsługiwany typ zmiennej" i niezainicjowaną tablicę arrRet
' - 3 "niezainicjowane obie tablice" i niezainicjowaną tablicę arrRet
' - 2 "niezainicjowana tablica arrInsert()" i tablicę arrRet będącą kopią tablicy arrBase()
' - 1 "niezainicjowana tablica arrBase()" i tablicę arrRet będącą kopią tablicy arrInsert()
'   0 "nieprzewidziany błąd" i nieokreślony stan tablicy arrRet
' • arrBase() - tablica bazowa, do której będziemy wstawiali drugą tablicę
' • arrInsert() - tablica wstawiana do pierwszej tablicy
' • lBefore - nr elementu (nie Index) tablicy, przed którym ma być wstawiona tablica


Public Function zbArrayIntoArrayMem( _
arrBase() As Long, arrInsert() As Long, _
arrRet() As Long, lBefore As Long) As Long
Dim lSizeArrBase As Long ' ilość elementów w tablicy bazowej
Dim lSizeArrIns As Long ' ilość elementów w tablicy wstawianej
Dim lMaxSizeBlock As Long  ' najdłuższy ciąg elementów do kopiowania
Dim lLenStart As Long ' długość początkowej części tablicy bazowej
Dim lLenIns As Long ' długość tablicy wstawianej
Dim lLenEnd As Long ' długość końcowej części tablicy bazowej
Dim lVarSize As Long ' długość w bajtach elementu tablicy
Dim hMem As Long ' uchwyt bloku pamięci
Dim pMem As Long ' wskaźnik do bloku pamięci
Dim lLBBase As Long ' najniższy dopuszczalny Indeks tablicy bazowej

' sprawdź, czy tablice są zainicjowane
On Error Resume Next
lSizeArrBase = (UBound(arrBase) - LBound(arrBase) + 1)
lSizeArrIns = (UBound(arrInsert) - LBound(arrInsert) + 1)
On Error GoTo 0
' obie niezainicjowane
If lSizeArrBase = 0 And lSizeArrIns = 0 Then
zbArrayIntoArrayMem = -3
Exit Function
End If
' pierwsza tablica niezainicjowana, zwróć drugą tablicę
If lSizeArrBase = 0 Then
Call zbCopyArrayInMem(arrInsert, arrRet)
zbArrayIntoArrayMem = -1
Exit Function
End If
' druga tablica niezainicjowana, zwróć pierwszą tablicę
If lSizeArrIns = 0 Then
Call zbCopyArrayInMem(arrBase, arrRet)
zbArrayIntoArrayMem = -2
Exit Function
End If

Select Case VarType(arrBase(LBound(arrBase)))
Case vbByte
lVarSize = 1
Case vbInteger, vbBoolean
lVarSize = 2
Case vbLong, vbSingle
lVarSize = 4
Case vbDouble, vbCurrency, vbDate
lVarSize = 8
Case Else
zbArrayIntoArrayMem = -4
Exit Function
End Select

' sprawdź poprawnowść miejsca wprowadzania drugiej tablicy
If lBefore < 1 Then lBefore = 1
If lBefore > lSizeArrBase Then lBefore = lSizeArrBase + 1

lLenStart = (lBefore - 1) * lVarSize
lLenIns = lSizeArrIns * lVarSize
lLenEnd = (lSizeArrBase - lBefore + 1) * lVarSize

' oblicz wielkość najmniejszego potrzebnego bloku pamięci
lMaxSizeBlock = lSizeArrIns * lVarSize
If lLenStart > lMaxSizeBlock Then lMaxSizeBlock = lLenStart
If lLenEnd > lMaxSizeBlock Then lMaxSizeBlock = lLenEnd

lLBBase = LBound(arrBase)
' ustaw rozmiar tablicy zwracanej
ReDim arrRet(lLBBase To lLBBase + lSizeArrBase + lSizeArrIns - 1)

' alokuj blok w pamięci i pobierz jego uchwyt
hMem = GlobalAlloc(GMEM_MOVEABLE, lMaxSizeBlock)
' zablokuj blok pamięci i pobierz wskaźnik do pierwszego bajta
pMem = GlobalLock(hMem)

' I - kopiuj pierwszą część tablicy do bloku pamięci
CopyMemory ByVal pMem, arrBase(lLBBase), lLenStart
' kopiuj zawartość bloku pamięci do arrRet()
CopyMemory arrRet(lLBBase), ByVal pMem, lLenStart

' II - kopiuj całą tablicę wstawianą do bloku pamięci
CopyMemory ByVal pMem, arrInsert(LBound(arrInsert)), lLenIns
lLBBase = lLBBase + lBefore - 1
' kopiuj zawartość bloku pamięci do arrRet()
CopyMemory arrRet(lLBBase), ByVal pMem, lLenIns

If lLenEnd > 0 Then
    ' III - kopiuj końcową cześć tablicy bazowej do bloku pamięci
    CopyMemory ByVal pMem, arrBase(lLBBase), lLenEnd
    ' kopiuj zawartość bloku pamięci do arrRet()
    CopyMemory arrRet(lLBBase + lSizeArrIns), _
ByVal pMem, lLenEnd
End If

Call GlobalUnlock(hMem)
Call GlobalFree(hMem)

If (UBound(arrRet) - LBound(arrRet) + 1) = _
lSizeArrBase + lSizeArrIns Then
    zbArrayIntoArrayMem = lSizeArrBase + lSizeArrIns
Else
    zbArrayIntoArrayMem = 0
End If

End Function

Porównanie szybkości obu funkcji dla tablicy 1 000 000 elementowej
TypzbArray....ForNextzbArray....MemMet.I/Met.II
Byte523 ms 33 ms15,8
Integer575 ms 68 ms 8,5
Long581 ms131 ms 4,4
Double648 ms235 ms 2,8

 ΔΔΔ 

 

5.13 Jak przekonwertować czas uniwersalny UTC na czas lokalny i odwrotnie ?

Private Declare Function SystemTimeToFileTime Lib _
"kernel32" _
(lpSystemTime As SYSTEMTIME, _
lpFileTime As FILETIME) As Long
Private Declare Function FileTimeToLocalFileTime Lib _
"kernel32" _
(lpFileTime As FILETIME, _
lpLocalFileTime As FILETIME) As Long
Private Declare Function LocalFileTimeToFileTime Lib _
"kernel32" _
(lpLocalFileTime As FILETIME, _
lpFileTime As FILETIME) As Long
Private Declare Function FileTimeToSystemTime Lib _
"kernel32" _
(lpFileTime As FILETIME, _
lpSystemTime As SYSTEMTIME) As Long

Private Type FILETIME
    dwLowDateTime As Long
    dwHighDateTime As Long
End Type

Private Type SYSTEMTIME
wYear As Integer
wMonth As Integer
wDayOfWeek As Integer
wDay As Integer
wHour As Integer
wMinute As Integer
wSecond As Integer
wMilliseconds As Integer
End Type


' konwertuje czas uniwersalny UTC na czas lokalny
Public Function zbUTCDateToLocalDate(ByVal dt As Date) As Date
Dim st As SYSTEMTIME
Dim ftUTC As FILETIME
Dim ftLocal As FILETIME

' konwertuj DateTime na SYSTEMTIME
With st
.wYear = Year(dt)
.wMonth = Month(dt)
.wDay = Day(dt)
.wHour = Hour(dt)
.wMinute = Minute(dt)
.wSecond = Second(dt)
End With

' konwertuj SYSTEMTIME na FILETIME
SystemTimeToFileTime st, ftUTC
' konwertuj czas UTC na lokalny czas
FileTimeToLocalFileTime ftUTC, ftLocal
' konwertuj FILETIME na SYSTEMTIME
FileTimeToSystemTime ftLocal, st

' konwertuj SYSTEMTIME na DateTime
zbUTCDateToLocalDate = CDate( _
CDbl(DateSerial( _
st.wYear, st.wMonth, st.wDay)) + _
CDbl(TimeSerial( _
st.wHour, st.wMinute, st.wSecond)))

End Function


' konwertuje czas lokalny na czas uniwersalny UTC
Public Function zbLocalDateToUTCDate(ByVal dt As Date) As Date
Dim st As SYSTEMTIME
Dim ftUTC As FILETIME
Dim ftLocal As FILETIME

' konwertuj DateTime na SYSTEMTIME
With st
.wYear = Year(dt)
.wMonth = Month(dt)
.wDay = Day(dt)
.wHour = Hour(dt)
.wMinute = Minute(dt)
.wSecond = Second(dt)
End With

' konwertuj SYSTEMTIME na FILETIME
SystemTimeToFileTime st, ftLocal
' konwertuj czas lokalny na czas UTC
LocalFileTimeToFileTime ftLocal, ftUTC
' konwertuj FILETIME na SYSTEMTIME
FileTimeToSystemTime ftUTC, st

' konwertuj SYSTEMTIME na DateTime
zbLocalDateToUTCDate = CDate( _
CDbl(DateSerial( _
st.wYear, st.wMonth, st.wDay)) + _
CDbl(TimeSerial( _
st.wHour, st.wMinute, st.wSecond)))

End Function

 ΔΔΔ 

 

5.14 Jak pobrać separator daty, format daty krótkiej, ilość dni w miesiącu, nazwy miesięcy, nazwy dni tygodnia, pierwszy pełny tydzień w roku ?

Private Declare Function GetLocaleInfo Lib _
"kernel32" Alias "GetLocaleInfoA" _
(ByVal Locale As Long, _
ByVal LCType As Long, _
ByVal lpLCData As String, _
ByVal cchData As Long) As Long

Private Const LOCALE_USER_DEFAULT& = &H400
Private Const LOCALE_SDATE = &H1D
Private Const MY_SIZE_BUFFER As Long = 255


' zwraca separator krótkiego formatu Daty
Public Function zbGetShDtSep() As String
Dim lRet As Long

zbGetShDtSep = String(MY_SIZE_BUFFER, vbNullChar)
lRet = GetLocaleInfo(LOCALE_USER_DEFAULT, _
LOCALE_SDATE, _
zbGetShDtSep, MY_SIZE_BUFFER)
zbGetShDtSep = Left$(zbGetShDtSep, lRet - 1)

End Function


' jeżeli nie chcemy korzystać z API możemy spróbować pobrać znak separatora z ciągu znaków będącm odpowiednio sformatowaną datą
Public Function zbGetShDtSep_1() As String

    ' pobierz separator daty (trzeci znak za dwucyfrowym oznaczeniem dnia)
    zbGetShDtSep_1 = Mid$(Format$(DateSerial(12, 12, 12), _
"dd/MM/yy"), 3, 1)

End Function


' zwraca pełną nazwę miesiąca
Public Function NameMonth(iMonth As Integer) As String

    NameMonth = Format$((DateSerial(Year(Now()), _
iMonth, 1)), "MMMM")

End Function


' zwraca pełną nazwę dnia tygodnia
Public Function NameDay(dt As Date) As String

    NameDay = Format$((DateSerial(Year(dt), _
Month(dt), Day(dt))), "dddd")

End Function


' zwraca ilość dni w danym miesiącu
Public Function DaysOfMonth(iYear As Integer, _
iMonth As Integer) As Integer

    DaysOfMonth = Day(DateSerial(iYear, _
iMonth + 1, 0))

End Function


' zwraca w postaci opisowej (dd.MM.rr) format daty krótkiej
Public Function zbGetShDateFormat() As String
Dim sDtSep As String * 1
Dim aRet() As String
Dim sDtFormat As String
Dim lLen As Long
Dim i As Long

' pobierz separator daty
sDtSep = Mid$(Format$(DateSerial(12, 12, 12), "dd/MM/yy"), 3, 1)
' rozdziel elementy daty w/m separatora daty
' zbSplit DateSerial(3, 2, 1), aRet(), sDtSep, , vbTextCompare
aRet = Split(DateSerial(3, 2, 1), sDtSep, , vbTextCompare)

' sprawdzaj kolejno elementy składowe daty
For i = LBound(aRet) To UBound(aRet)
If IsNumeric(aRet(i)) Then
Select Case CLng(Right$(aRet(i), 2))
Case 1 ' dzień 1
sDtFormat = sDtFormat & String(Len(aRet(i)), "d") & sDtSep
Case 2 ' miesiąc luty
sDtFormat = sDtFormat & String(Len(aRet(i)), "M") & sDtSep
Case 3 ' rok 2003
sDtFormat = sDtFormat & String(Len(aRet(i)), "r") & sDtSep
Case Else
End Select
Else
' literowe oznaczenie miesiąca 'lut' lub 'luty'
lLen = Len(aRet(i)): If lLen > 4 Then lLen = 4
sDtFormat = sDtFormat & String(lLen, "M") & sDtSep
End If
Next

zbGetShDateFormat = Left$(sDtFormat, Len(sDtFormat) - 1)

End Function


' zwraca datę dla tygodnia zaczynający się od dnia iFirstDayOfWeek,
' począwszy od daty wejściowej, jeżeli szukany tydzień wypada
' na przełomie lat to zwraca datę pierwszego dnia tygodnia w następnym roku

Function zbGetFullWeekDate(dtIn As Date, _
Optional iFirstDayOfWeek As Integer = vbSunday) As Date
Dim dtCheckDate As Date
Dim iYear As Integer
Dim iDay As Integer

iYear = Year(dtIn)
dtCheckDate = dtIn

iDay = WeekDay(dtCheckDate, iFirstDayOfWeek)
Do Until iDay = 1
dtCheckDate = dtCheckDate + 1
iDay = WeekDay(dtCheckDate, iFirstDayOfWeek)
Loop

' może to być ostatni tydzień na przełomie roku
If Month(dtCheckDate) = 12 Then
' dodaj sześć dni i jeżeli styczeń, to dodaj do daty tydzień
If Month(dtCheckDate + 6) = 1 Then
dtCheckDate = dtCheckDate + 7
End If
End If

zbGetFullWeekDate = dtCheckDate

End Function


' przykładowe wywołania:
Private Sub btnTest_Click()
Dim i As Long
Dim dt As Date

Debug.Print "separator daty krótkiej: "; zbGetShDtSep
Debug.Print "separator daty krótkiej: "; zbGetShDtSep_1
Debug.Print "format daty krótkiej: "; zbGetShDateFormat

' wyświetl nazwy miesięcy
For i = 1 To 12
    Debug.Print i; NameMonth(CInt(i));
    Debug.Print ", dni: "; DaysOfMonth(Year(Now), CInt(i))
Next

' pobierz pierwszy pełny tydzień roku (od poniedziałku)
dt = zbGetFullWeekDate(#1/1/2009#, vbMonday)
Debug.Print "pierwszy poniedziałek w roku 2009 ", dt

' wyświetl nazwy dni tygodnia
For i = 0 To 6
    Debug.Print i + 1, NameDay(dt + i)
Next

DoCmd.RunCommand acCmdDebugWindow

End Sub

 ΔΔΔ