Viser opslag med etiketten dato. Vis alle opslag
Viser opslag med etiketten dato. Vis alle opslag

fredag den 21. oktober 2016

Datoer i Calc med makroer

I makroen hvor vi importerede CSV-filen ved at indlæse linje for linje, anvendte vi the_cell.Value = [datoværdi]. Lad os kige lidt mere på, hvordan datoer håndteres i LibreOffice i makroer.

Vi skal se dato-format problemet i to perspektiver:
1) Datoformatet i variable i makroen
2) Datoen, når den indsættes i eller læses fra en celle.

Det er vigtigt at skelne tydeligt mellem de to perspektiver, da resultatet ellers kan vise sig overraskende (forkert).

Denne artikel omhandler andet punkt, nemlig håndtering af datoer i regnearkets celler.

I eksemplet importerede vi datoen fra en CSV-fil, og derfor var udgangspuntket en tekststreng, som vi så behandlerede således:
t= split(s, "-", 3)
s=DateSerial(t(2), t(1), t(0))


Og vi indsatte så resultatet i cellen sådan:
my_cell.String=s

Det betyder at resultatet er en tekststreng (.String).

Vi burde have gjort det anderledes, nemlig med
my_cell.Value=s
Problemet er dog at resultatet vises i regnearket som datoværdier, f.eks. 42659

Det håndterer vi ved at formatere cellen således:
my_cell.Value=s
my_cell.NumberFormat=36   


Tallet .NumberFormat=36 viser datoen som 09-10-2016, hvilket er præcist som ønsket. Tallet 36 fandt jeg frem til ved at formatere en celle manuelt, og så aflæse tallet
Print my_cell.NumberFormat

Her er en makro som demonstrerer det meste:

REM  *****  BASIC  *****

Sub Main
Dim my_date As Date

my_doc = ThisComponent
my_sheets = my_doc.Sheets
antal=my_sheets.count

If NOT my_sheets.hasbyName("Dato") Then

my_sheets.insertNewByName("Dato", antal)

End If

the_sheet = my_sheets.getByName("Dato")
the_sheet.TabColor= RGB(0, 0, 100)

rem --------------------
my_date = DateValue("20 Jan 2016")
my_cell = the_sheet.getCellbyPosition(1,1)
my_cell.Value = my_date
my_cell.NumberFormat=36   

Print my_cell.Value
Print CDate(my_cell.Value)
Print IsDate(my_cell.Value)

End Sub



Lidt om datoer (i makro)

I makroen hvor vi importerede CSV-filen ved at indlæse linje for linje, anvendte vi the_cell.Value = [datoværdi]. Lad os kigge lidt mere på, hvordan datoer håndteres i LibreOffice i makroer.

Vi skal se dato-format problemet i to perspektiver:
1) Datoformatet i variable i makroen
2) Datoen, når den indsættes i eller læses fra en celle.

Det er vigtigt at skelne tydeligt mellem de to perspektiver, da resultatet ellers kan vise sig overraskende (forkert).

Denne artikel omhandler første punkt, nemlig håndtering og bearbejdning af datoer med makroer. Datofunktionerne er ikke afhængige af Calc, men fungerer også med datoer i f.eks. Writer.

I makroen, når vi arbejder med datoer i variable, kan vi tænk på datoer som to forskellige typer tekst: En lokaliseret (dansk, engelsk, ...) version og en international version (ISO 8601 date format). I bund og grund fungerer begge typer fuldstændig uden problemer, men lokaliseret dato er standard, og ISO 8601 (YYYY-MM-DD) er kun relevant, når vi vælger det eksplicit.

Ikke desto mindre regner LibreOffice med en intern dato-værdi, hvor 0 svarer til 29/12/1899: -1
30/12/1899: 0
31/12/1899: 1
01/01/1900: 2
01/02/1900: 3
01/01/2001: 36892

Datokonvertering:
  • CDate: Konverter et tal (datoværdi) eller en tekst til en dato.
  • DateValue: Konverterer en formateret tekst (i intervallet 1. december 1, 1582 til 31 December 9999) til en dato-værdi, som ikke har tidsinformationer. Datoen 1. december 1582 svarer ca. til det tidspunkt, hvor den gregorianske kalender blev indført. Se https://da.wikipedia.org/wiki/Gregorianske_kalender
  • CDateFromIso: Konverterer til en dato fra en ISO 8601-dato.
  • CDateToIso: Konverterer en dato til en ISO 8601-dato.
  • IsDate: Er teksten korrekt formateret som dato? Brug IsDate til at afprøve om en tekst indeholder en korrekt formateret dato.
Datoer lige omkring 30/12 1899 kan udløse fejl i tidligere versioner af LibreOffice, men det burde ikke være et problem i nyere versioner.

Når vi så har en dato(værdi), kan vi udlede nogle interessante informationer:
  • Year(date): Returnerer årstallet af en dato som et heltal.
  • Month(date): Returnerer månedsnummeret af en dato som et heltal.
  • Day(date): Returnerer dagstallet af en dato som et heltal.
  • WeekDay(date): Returnerer et heltal fra 1 til 7, som svarer til dage i ugen (søndag til lørdag).
Eksempel
Sub test
my_date=DateValue("19 Januar 1965")
Print isDate(my_date) 'True
Print my_date         '19/01/1965
Print year(my_date)   '1965
End sub


Funktionen DatePart gør noget lignende, nemlig udleder en konkret information
Print DatePart("yyyy",my_date) 'Årstal
Print DatePart("q",my_date)    'Kvartal
Print DatePart("m",my_date)    'Måned
Print DatePart("y",my_date)    'dag i året
Print DatePart("w",my_date)    'Ugedag
Print DatePart("d",my_date)    'Dag


DatePart splitter altså en dato ad i enkeltdele, og vi har en tilsvarende funktion til at samle delene i en dato igen:
Print DateSerial(1965, 1, 19)  '19/01/1965

Vær opmærksom på at DateSerial har en fejl, som betyder at datoen før år 100 konverteres forkert, idet der lægges 1900 til årstallet:
Print DateSerial(90, 1, 19)    '19/01/1990

Vi kan manipulere datoen med funktionen DateAdd sådan:
DateAdd("d", 3, my_date)       'Læg tre dage til datoen
DateAdd("m", 3, my_date)       'Læg 3 måneder til datoen
DateAdd("yyyy", -3, my_date)   'Træk 3 år fra datoen


DateDiff anvender tilsvarende tekstparameter til at formatere svaret fra en subtraktion:
my_date=DateValue("19 Januar 1965")
Print DateDiff("yyyy", my_date, Date)  'Jeg er 51 år
Print DateDiff("d",    my_date, Date)  'Mere præcist 18903 dage