BLOG

Softwareontwikkeling

7 tips om fouten met tijden en tijdzones te voorkomen in software

2 juni 2020

Er is waarschijnlijk niets dat zoveel bugs veroorzaakt als datums en tijden. Laatst sprak ik nog met een klant die internationaal opereert en  steeds maar weer problemen tegenkomt met betrekking tot tijdsverschillen in de verschillende software oplossingen die ze hebben draaien. Maar waarom is dit nou zo lastig?

Toevallig kwam op die vraag een antwoord toen ik online meekeek bij PHP Russia. Andreas Heigl vertelde in zijn talk ‘Time is an illusion (lunchtime doubly so)’ over de complexiteit van omgaan met tijd in software (specifiek in PHP) en gaf enkele praktische tips.

Deze tips wil ik jullie natuurlijk niet onthouden. In dit artikel behandel ik  enkele belangrijke tips van hem en vul ik die aan met tips uit mijn eigen ervaringen.

1. Gebruik zoveel mogelijk standaardfuncties

De meeste programmeertalen hebben geweldige standaardbibliotheken om om te gaan met tijd. Gebruik deze! Ze zijn vaak ver doorontwikkeld, bugvrij en houden op de achtergrond rekening met complexiteit die je misschien niet kent of waar je niet bij stilstaat. Door de standaardbibliotheek te gebruiken voorkom je dus bugs.

Binnen PHP is er ook nog het onderscheid tussen de low-level (C-like) tijdfuncties en de meer high-level DateTime functies en objecten. Gebruik hier zo vaak mogelijk de DateTime functies, aangezien het maken van fouten hiermee lastiger is.

2. Sla alles op naar UTC, verwerk alles als UTC en zet om naar lokale tijd bij het weergeven

Veel fouten worden veroorzaakt door verschillen in tijdzones. Ik heb bijvoorbeeld problemen gezien waarbij vertalingen tussen tijdzones niet goed liepen, maar ook problemen waarbij een deel van de applicatie de servertijd aanhoudt en andere de tijdzone van de database (die kunnen verschillen!).

Om de complexiteit te verlagen is het eigenlijk altijd een goed idee om op de backend overal UTC te gebruiken. UTC is de ‘standaard’-tijdzone voor software, en door één tijdzone te gebruiken worden berekeningen en redeneringen met tijd veel simpeler. Zet de tijdzone van je applicatie en database altijd naar UTC, om fouten te voorkomen.

Als je een applicatie bouwt die binnen één tijdzone gebruikt wordt en die ook nooit in een andere tijdzone gebruikt zal worden, is het ook acceptabel om die specifieke tijdzone overal op de backend en de frontend te gebruiken. Wees in dat geval wel expliciet, zoals ik verder beschrijf bij tip 6.

3. Geef in een internationale context altijd de tijdzone aan

Bij bugs denken we vaak aan technische fouten, waarbij de programmeur simpelweg een fout heeft geschreven in de code. Maar dat is eigenlijk geen goed beeld van bugs. Veel bugs ontstaan namelijk door een fout in de functionaliteit of door een misverstand tussen de programmeur en de ‘business’. 

Eén van de dingen die je kunt doen om veel complexiteit aan de functionele kant te verwijderen, is het expliciet aangeven van de tijdzone. Vooral in een internationale omgeving is het wel eens minder voor de hand liggend welke tijdzone we weergeven. Denk bijvoorbeeld aan een situatie waarin ik vanuit Nederland kijk in een administratief systeem van de administratieve afdeling in Polen, naar een afspraak van een Spaanse klant die een afspraak heeft bij tj een vestiging in Portugal. Welke tijdzone houdt de tijd van deze afspraak dan aan? Functioneel zijn er meerdere antwoorden te beargumenteren, maar door expliciet in de software de tijdzone aan te geven wordt de verwarring tenminste weggenomen.

4. Check je assumpties – een dag is niet altijd 24 uur!

De quote ‘Assumption is the mother of all **** ups’ (Mr. Eugene Lewis Fordsworthe) is heel populair onder programmeurs. Ik denk dat dit niet zozeer is omdat we allemaal zo diep geïnteresseerd zijn in filosofie, maar vooral omdat het zo herkenbaar is. De meeste bugs die wij creëren worden veroorzaakt doordat ergens in het proces: bij de persoon die een functioneel ontwerp maakt, de programmeur die het ontwikkelt, de architect die het reviewt of de gebruiker die ermee werkt een foutieve assumptie werd gemaakt. Het toetsen van assumpties met feiten is erg belangrijk en dit is zeker ook het geval met datums en tijden.

Heel veel zaken die wij zien als feiten zijn simpelweg niet waar. Heeft een jaar 365 dagen? (nee) Heeft een dag altijd 24 uur? (nee) Valt een week altijd in één maand? (absoluut nee) en er zijn nog tientallen andere voorbeelden. Teveel om in dit artikel te noemen, maar als je ze wilt leren kennen is de video van Tom Scott een goed startpunt.

Het is heel belangrijk om, als je met tijd werkt, stil te staan bij alle assumpties die je in je software stopt. Juist omdat er zo ongelofelijk veel uitzonderingen zijn binnen tijden, datums en tijdzones. Sta stil bij de assumpties, check ze, en documenteer ze. En is er een functionele wijziging mogelijk waardoor je minder ‘enge’ assumpties hoeft te maken? Stel hem dan zeker voor! Misschien bespaar je ook de business er wel veel hoofdpijn mee.

5. Zorg dat je tijdzone informatie up-to-date is

Tijdzones veranderen (vaak). Je zou het niet denken, maar er is zelfs een website die alle wijzigingen bijhoudt. Gelukkig hoeven we onze software niet bij elke wijziging aan te passen. Het databasesysteem, de programmeertaal, het operating system en/of de software library doen dit voor je. Maar om deze nieuwe tijdzone informatie te ontvangen, is het wel erg belangrijk om je software te updaten. Doe dit dus ook! Verouderde infrastructuur (zoals een verouderde PHP-versie) kan ernstige bugs veroorzaken door verouderde tijdzone informatie.

6. Gebruik nooit server-tijd, wees expliciet met de tijdzones.

Het is erg aantrekkelijk om de server-tijd aan te houden. Sterker nog, in veel programmeertalen en omgevingen is het de standaard. Maar er zijn veel gevaren. Wat nu als de server fysiek in een ander land staat, en die tijd aanhoudt? Of wat als de software wordt gemigreerd naar een andere machine? We willen hier niet van afhankelijk zijn. De tijdzone zou moeten worden gezet door de software, niet het platform waarop het draait.

7. Gebruik zo vaak mogelijk DateTimeImmutable.

Andreas noemde DateTimeImmutable ‘DateTime zoals het had moeten zijn’ en ik weet dat veel programmeurs het met hem eens zijn! Verschillende collega’s bij Senet zijn mondig voorstanders van immutable objecten, en dan vooral bij datums en tijden. 

Maar wat zijn immutable objecten, en wat is het verschil? Bij het aanroepen van een methode bij een normaal object, wordt de waarde van dat object aangepast. Het object zelf verandert dus, en is ‘Mutable’ (muteerbaar). Bij een ‘Immutable’ object kan de waarde niet veranderd worden. Elke methode die wordt aangeroepen resulteert in een nieuw object, met een nieuwe waarde. Hierdoor wordt code makkelijker te lezen, en worden ‘side-effects’ voorkomen. Hiermee wordt de onderstaande bug bijvoorbeeld voorkomen:

<?php 
$today = new \DateTime(); 
$tomorrow = $today->modify('+1 day');

var_dump($today->format('d-m-Y'));
var_dump($tomorrow->format('d-m-Y));

/* Output:
string(10) "14-05-2020"
string(10) "14-05-2020"
*/

$todayImmutable = new \DateTimeImmutable();
$tomorrowImmutable = $todayImmutable->modify('+1 day');

var_dump($todayImmutable->format('d-m-Y'));
var_dump($tomorrowImmutable->format('d-m-Y'));

/* Output:
string(10) "13-05-2020"
string(10) "14-05-2020"
*/

Problemen met datums en tijden voor eens en altijd verhelpen?

Senet heeft jarenlange expertise met maatwerk software, ook in een internationale context. Wij kunnen u helpen om uw software zo op te zetten dat problemen met datums en tijden worden voorkomen. Meer weten? Neem contact met ons op!

Interesse in een gesprek?

neem contact op met Geurt Jan van Ek

Neem contact op

Zie onze privacyverklaring.