A.E.Veltstra
07/01/2002
De sql-motor van MS Access verwacht Amerikaanse datumnotatie als invoer van een datumveld. In Nederland gebruiken we regelmatig Nederlandse datumnotatie bij weergave en invoer. Meer dan eens worden hierdoor de maand en de dag verwisseld op een asp-pagina. Als jou dat ook overkomt, heb ik misschien de definitieve oplossing.
Samenvatting
Als je zit te stoeien met weergave en opslag van datums in verschillende notatieformaten, vergeet dan de datum zelf en werk binnen je scripts met de double die door Access gebruikt wordt om de datum op te slaan.
Het probleem
Ik heb de UK-versie van MS Access 97. De tabel "tblNews" in een Access database bestaat uit twee velden: NDatum (een datum) en NBody (een tekst). NDatum is geformatteerd als "short date", korte datumnotatie. Deze notatiewijze is gebaseerd op de datuminstellingen van Windows, met een minimum aan datuminformatie. Op mijn computer is de korte datumnotatie geformatteerd als "d-m-yy".
Ik heb twee asp's met als scripttaal MS VBScript. De eerste asp is een overzichtslijst van records uit de tabel tblNews. De records zijn aflopend gesorteerd op NDatum. De webmaster mag in de lijst op de datum klikken, om het nieuwsbericht te wijzigen in de tweede asp. Als koppeling tussen de overzichtslijst en het wijzigformulier wordt de datum van het bericht doorgegeven in de querystring.
In het wijzigformulier wordt uit de tabel tblNews het nieuwsbericht opgepikt dat dezelfde datum heeft als aan de querystring is doorgegeven. Nu staat het wijzigformulier toe, dat de datum van het nieuwsbericht gewijzigd wordt. Dus ik heb een tekstvak dat de datum weergeeft en laat wijzigen.
Als ik de datum uit het veld NDatum zonder meer weergeef, wordt er vanuit Access een standaard datumtype geleverd, geformatteerd als internationale datum. Access trekt zich niets aan van de datumformaatinstellingen in de tabel. Deze datum wordt afgeleverd aan de asp.dll, de bibliotheek op de webserver die alle asp-scripts afhandelt. De asp.dll zet de ontvangen datum om in een string, zodat ze getoond kan worden in html. Daarbij houdt de asp.dll rekening met de globale datuminstelling van de webserver. In mijn geval is dat Amerikaans. Met andere woorden: als de overzichtslijst getoond wordt, staan daar Amerikaanse datums in.
Als ik dat niet wil, kan ik de datums een nieuw formaat geven. De recordset die de lijst toont, levert de datum gelukkig als standaard datumtype op. Deze datum kan uiteen worden gerafeld met de Day(), Month() en Year() functies van VBScript. Het resultaat van deze functies wordt in een string gezet, die in de html verschijnt. Zo genereer ik Nederlands datumformaat.
Nu mag ik dat Nederlandse datumformaat wel tonen, maar niet gebruiken om het nieuwsbericht mee op te vragen in het wijzigformulier. Waarom niet? Omdat de sql-motor van Access Amerikaanse datumnotatie verwacht als criteriumonderdeel van de Where-clausule. Dus de querystring blijft de Amerikaanse datum ontvangen.
Het wijzigformulier pikt de gewenste datum op uit de querystring, vraagt het bijbehorende nieuwsbericht op, en toont deze waarden in een text input en een text area element. Het tonen van de datum gebeurt uiteraard na herformattering naar het Nederlands. De webmaster verandert de datum, verandert het bericht, en slaat het bericht op. En waarempel, de maand en de dag verwisselen van plek. De ingevoerde datum is namelijk in het Nederlands, terwijl Access een Amerikaanse datum verwacht.
Een oplossing, die niet werkt...
Je zou verwachten, dat je de ingevoerde datum oppikt uit het form, er met de Day(), Month() en Year() functies de juiste waarden uitpikt en deze in de juiste (Amerikaanse) volgorde doorgeeft aan de sql-instructie. Helaas werkt dat niet. De maand en dag blijven omdraaien. Waarom? Omdat de asp.dll de ingegeven datum vergelijkt met de globale datuminstelling van de computer, die in mijn geval Amerikaans is. Hij ziet het eerste getal als maand, en het tweede als dag. Dat is de manier waarop Day() en Month() werken, en dat is zoals Micro$oft wil dat het werkt.
Een oplossing die ook niet werkt...
Dan zou je denken: je weet toch hoe die Nederlandse datum eruitziet. Gebruik gewoon de Mid() functie om de juiste getallen uit de ingevoerde datum te trekken en voer die in Amerikaanse volgorde in in de sql-instructie. Helaas werkt dat ook niet. Je geeft namelijk nog altijd een datum door aan de asp.dll, die door hem omgezet wordt in een string met datuminformatie. De omzet gebeurt op basis van de datuminstelling van de computer en dus verkeerd om. En als je geen datum doorgeeft, maar stukjes datumstring rechtstreeks in de sql-instructie invoert, zou het wel moeten werken, ware het niet dat de gebruiker in staat is allerlei tekst in te voeren die niet lijkt op datuminformatie om vervolgens de database te vermoorden. En het laatste dat ik wil is mijn asp vervuilen met overbodige controles.
De oplossing die wel werkt: opslaan
Ten eerste trek ik de datum al uit elkaar nog voordat hij ingevoerd is. Ik toon drie tekstvakjes naast elkaar: een voor de dag, een voor de maand, een voor het jaar. De nieuwe datum is zo automatisch opgesplitst in drie herkenbare delen. Bij het opslaan worden de delen samengevoegd met de DateSerial() methode. Deze functie ontvangt de dag, de maand en het jaar gescheiden, maar levert de internationale datumnotatie op. Ik wil Amerikaanse datumnotatie en ik wist al, dat Day() en Month() niet het gewenste effect opleveren.
En plotseling herinner ik, dat Access de datum helemaal niet als datum opslaat, maar als notatieonafhankelijke Double Integer. Dus snel een CDbl() om de DateSerial() geplaatst en dit getal als numeriek gegeven doorgegeven aan de sql-instructie. Het werkt! Het gedoe met verschillende datumnotaties kan gewoon achterwege gelaten worden als je werkt met de Double waarmee Access een datum opslaat.
De oplossing die wel werkt: tonen
Echter, nu de in te voeren datum in drie vakjes wordt getoond, ben ik verplicht de datum die uit de overzichtslijst werd opgevraagd, uit elkaar te trekken. En ook hier gaan Day() en Month() de mist in, om exact dezelfde reden als boven. Maar wacht eens even. Als Access de datum als Double opslaat, die onafhankelijk werkt van de notatiemethode, dan ik ik die misschien ook gebruiken om de dag en de maand in de juiste volgorde uit te vragen... Jawel, dat gaat. Maar dan moet ik wel de double-waarde van de datum doorgeven in de querystring in plaats van de Amerikaanse datum. En dan moet ik in het wijzigformulier het nieuwsbericht ook opvragen door die double aan de select-instructie mee te geven als numeriek criterium. De database reageert prima op deze wijziging. Ook Day() en Month() reageren prima op de double.
Samenvatting
Als je zit te stoeien met weergave en opslag van datums in verschillende notatieformaten, vergeet dan de datum zelf en werk binnen je scripts met de double die door Access gebruikt wordt om de datum op te slaan.