Ik heb een paar keer problemen gehad met datum/tijd in Gambas, meestal gecombineerd met het opslaan in een databank, of er terug uit ophalen (*).
Bug
Op een bepaald moment werd er een bug gemeld op de mailinglist:
[Gambas Bug Tracker] Bug #1321: Converting date to string behavior change between 3.10 and 3.11
Gebruikers hadden ontdekt dat bepaalde programma’s, bepaalde broncode, niet meer werkte na een update van Gambas3 (overgang 3.10 naar 3.11 of hoger).
De bug-melding werd verworpen.
Correctie
Maar die verandering werd bevestigd; het was echter geen bug; ze was het gevolg van het verbeteren van een bug; er zat een fout in vroeger Gambas-code, en die was met deze versie-wissel gecorrigeerd, waardoor Gambas inderdaad anders reageert in sommige situaties.
Str() Val() Format() en Date() maken gebruik van de “locale”, de instellingen van de “desktop” (taal/land/tijd/etc).
CStr() gebruikt de UTC tijd.
Dus je moet kijken naar de instelling van de database en die van je desktop, bv GMT+0200
.
In één programma CDate() en Date() mengen zal waarschijnlijk problemen geven.
De interne manier om een datum of tijd bij te houden is een getal, relatief tov een denkbeeldig nulpunt.
Met Format(), Date() maak je een interpretatie waarin je tijdzone meegenomen wordt om het voor jou “aanschouwelijk juist” te maken.
Bv in Groot-Brittanië is een datum/tijd opgeslagen in een record.
Als jij die opvraagt en toont met Format() dan krijg je de tijd die het in jouw tijdszone was, niet wat letterlijk opgeslagen is in de database.
Je moet dus ook opletten (voor het verschil)
– of je de database een datum laat opslaan, bv automatisch (instelling db server) met de instelling timestamp.
– of je zelf een datum naar de database stuurt als tekst: .. values('2024-01-01 01:14:18')
– of je kan in je SQL statement de opdracht voor een datum geven
Database
De database (mysql/mariadb) heeft 5 tijdsgebonden opslagvormen (kolom):
- DATE = aleen de datum (1000-01-01-9999-12-31)
- DATETIME = datum + tijd (1000..:..- 9999...:..)
- TIMESTAMP datum + tijd (1970-20238!!!!)
- YEAR : alleen een jaartal (1901-2155)
- TIME : alleen een tijd (getal -838.. tot + 838.. ong 35 dagen)
Het 2038 probleem
Het hangt er natuurlijk een beetje vanaf wat je met die datums wil doen, en daarom moet je rekening houden met hun bereik, meestal vooral met hun hoogst mogelijke waarde, die voor sommige formaten gevaarlijk dichtbij komt.
Als je de datum enkel opslaat als leesbare informatie voor de programmeur, is 2038 van timestamp geen probleem, maar als het een veld is waar je verder conclusies uit gaat trekken gebaseerd op vergelijkingen met andere datum/tijd, berekeningen maken, sorteren enz, dan zie je de problemen al opduiken nog voor je op pensioen* bent. En timestamp is ook zuiniger met opslagruimte.
(* bv als je geboren bent na de default pc BIOS datum van 04-01-1980)
DATETIME is dus het veiligere alternatief, maar let op met de tijdszone.
Timestamp probeert de “huidige” tijdszone om te zetten naar UTC om de waarde op te slaan in de database, en terug te zetten naar de tijdszone (van de server**) bij het opvragen.
** dus niet de zone van de client als je bv vanop afstand gegevens opvraagt
Tijdzone
Vanaf Gambas 3.18 kan de tijdzone meegegeven worden:
(Old date string representation) space [ UTC | GMT ] [ + | - ] HH [ :MM ]
Om de algehele verwarring rond datums, (interne) opslag en weergave, tijdzone en formaten aan te pakken werd deze wiki pagina gemaakt, met oa:
Datums zijn geen strings
– Interne voorstelling
– Functies die werken met U.T.C. en American date format
– Functies die werken met local time
– Impliciete omvorming
– Datums zijn getallen
– Null datums en datums met alleen een tijdsdeel
– Datums bewaren
– Datums bewaren in een binair bestand
– Datums bewaren in een tekstbestand
– Datums en kalenders
Voor selectie van een datum, zie ook de wiki pagina over kalenders.
Bronnen
– mailinglist en bugtracker
https://lists.gambas-basic.org/pipermail/user/2018-May/064153.html
Datetimes versus timestamps in MySQL
https://gambaswiki.org/ wiki/doc/date, wiki/doc/calendar