Jump to content

Best practice tijdzones


Recommended Posts

Even peilen:

Wat is de beste benadering voor een applicatie dat in meerdere tijdszones wordt gebruikt? 

We hebben natuurlijk Get(CurrentTimeUTCMilliseconds) om een universele tijd vast te leggen, maar dat leidt wel tot een conversievraagstuk om leesbare tijden in het systeem weer te geven (waarvoor Menno overigens een mooie CF heeft gemaakt).

De standaard entry-optie voor tijdstempels uitschakelen en calculatie instellen op Get(CurrentHostTimestamp) is ook een optie, maar leidt ook tot een display probleem als de eindgebruiker in een andere tijdzone zit.

Benieuwd naar jullie inzichten!

Link to comment

Voor mijzelf is evident dat je hier alleen nog de host timestamp kunt gebruiken. Dit om ervoor te zorgen dat de opgeslagen tijden eenduidig zijn. Voor de eind gebruiker kun je een berekend veld gebruiken dat er de eigen tijd voor die gebruiker mee berekent. Dit is alleen voor de presentatie van dit gegeven.

Link to comment

Mijn CF berekent de DST zoals deze nu in het grootste deel van de EU wordt gebruikt. Je zou mijn CF dus eigenlijk moeten uitbreiden met een stukje waarmee je DST uitschakelt.

Verder is de opmerking van Banach óók zeer terecht. Wanneer je slechts één FMServer gebruikt is dat de meest eenvoudige manier om allemaal van dezelfde absolute tijd  gebruik te maken

Dat verandert helaas als je meerdere servers gebruikt en ze met alkaar gaat laten 'praten'. UTC vanuit FM(server) is dan ook niet betrouwbaar, omdat het voor veel systeembeheerders erg moeilijk is om de juiste tijd en tijdzone op een server in te stellen. Ze synchroniseren dan wel via NTP, maar als de basisinstellingen niet kloppen, krijg je toch een heel riedeltje problemen.

Voorbeeld: je hebt een host voor je virtuele machines, die heeft ook een tijdzone. De VM's zijn verschillende smaken Windows en Linux én ook nog eens op verschillende locaties en door verschilende personen op verschilllende werkstations aangemaakt en geconfigureerd. Het is een extreem voorbeeld, maar ik heb het aan de hand gehad en de tijdsverschillen zijn erg niet van de lucht en erg lastig op te lossen. Je moet echt alles doorlopen om de zaak synchroon te krijgen :-)

Link to comment

Dank jullie wel! Dit is waardevolle input.

Ik verkeerde in de onterechte veronderstelling dat Get(CurrentTimeUTCMilliseconds) een host-gebaseerde timestamp oplevert! Dat is dus niet zo en dat maakt het m.i. direct onbruikbaar voor absolute tijdsregistratie, tenzij je de functie op de FMS laat evalueren, wat mij enorm ingewikkelde rompslomp lijkt.

Ik volg Banach met zijn stelling: consequent gebruik van de host-timestamp en dus nooit meer de auto-entry tijdstempel aanvinken als je een multi-tijdzone systeem bouwt waarin tijd ertoe doet.

Vervolgens moet er dus voor alle gegevens waarvoor een datum/tijd wordt weergegeven een (unstored) calculatieveld worden gebruikt waarin de tijd wordt gecorrigeerd naar de lokale datum/tijd. Althans - als men de tijdstippen in lokale tijd moet kunnen duiden.

Kan me voorstellen dat je per sessie een tijdsverschil vastlegt ten opzichte van de hosttijd, om deze correctie mogelijk te maken. Je hoeft dan eigenlijk niet eens de tijdzone op zichzelf vast te leggen. Elk tijdsverschil is goed. 

Binnen het gesloten systeem van één server heb je daarmee het probleem waarschijnlijk opgelost. 

Bij niet gesloten systemen en data-sync op basis van timestamps heb je inderdaad het probleem van de tijdverschillen (al dan niet in verschillende tijdszones en DST). Zou me kunnen voorstellen dat je hier een zelfde soort benadering toepast als hierboven: per sessie eerst het tijdsverschil bepalen, en vervolgens bij elke vergelijking op recordsniveau de tijdsverschilfactor meenemen, in de vorm van een soort globale variabele, ook bij het overzetten van de data.  

Heb een dergelijke benadering nog niet eerder hoeven toe te passen. Wel gebruikte ik een minimale margetijd om niet op elke gedetecteerd tijdsverschil een record te laten syncen, juist omdat de klokken niet 100% gelijk lopen. Overigens vaak in combinatie met een hashcode om werkelijke wijzigingen te kunnen detecteren.

Link to comment
9 uren geleden, Marsau zei:

Kan me voorstellen dat je per sessie een tijdsverschil vastlegt ten opzichte van de hosttijd, om deze correctie mogelijk te maken. Je hoeft dan eigenlijk niet eens de tijdzone op zichzelf vast te leggen. Elk tijdsverschil is goed. 

Je moet dan wel corrigeren voor DST, die in verschillende landen op andere momenten ingaat en soms op andere tijden . . .

Link to comment

dat werkt alleen voor de huidige stamps, als je een lijst hebt van bv correspondentie die over een langere periode loopt dan kan het zijn dat er in die periode één of meerdere keren een correctie moet worden doorgevoerd vanwege de DST en dan moet je weten of er DST zat in de opgeslagen tijd, of dat er DST was bij de gebruiker.

Als je de datum op de server als UTM opslaat dan heb je 1 kant al afgedekt. hoef je alleen te weten wanneer DST bij de gebruiker was zodat je daarvoor kunt corrigeren.

Link to comment
Op 10-6-2022 om 14:25, Infomatics zei:

dat werkt alleen voor de huidige stamps, als je een lijst hebt van bv correspondentie die over een langere periode loopt dan kan het zijn dat er in die periode één of meerdere keren een correctie moet worden doorgevoerd vanwege de DST en dan moet je weten of er DST zat in de opgeslagen tijd, of dat er DST was bij de gebruiker.

 

Ok, dat is een hele terechte opmerking! Als je alles baseert op het tijdsverschil van een bepaald moment,  krijg je fouten met DST op de betreffende datum/tijdstip. 

Dan kom ik tot de volgende inrichting':

  1. enkel en alleen hosttime-stamps vastleggen: Get(CurrentHostTimestamp)
  2. in een UTC formaat. Let op. Get(CurrentTimeUTCMilliseconds) is hiervoor niet bruikbaar!
  3. voor datum/tijd weergave aparte unstored calculatievelden waarin de UTC tijd wordt geconverteerd op basis van de tijdszone en DST van de lokatie van de gebruiker.

Tijdszone en DST (wel/niet) moeten dan sessie-parameters worden. Wellicht kan je dan on-the-fly bepalen, maar voor makkelijker lijkt het om gebruikersrecords te gebruiken waarin het gegeven wordt opgeslagen.

M.i. is er een CF nodig dat Get(CurrentHostTimestamp) omzet in een UTC, aangezien Get(CurrentTimeUTCMilliseconds) de client klok gebruikt. 

Vervolgens kan de CF als die van Menno worden gebruikt om de UTC om te zetten naar lokale datum/tijd op de layouts: uitgebreid met het DST stuk.

Ik vroeg me af of het gebruik van UTC een noodzaak is, of je m.a.w. niet ook gewoon de lokale servertijd tot norm kan verheffen, en mutatis mutandis elke timestamp kan converteren naar de lokale timezone van de gebruiker. Ik denk echter dat je dan ook hetzelfde vraagstuk krijgt met DST.

Link to comment
7 hours ago, Marsau said:

Ik vroeg me af of het gebruik van UTC een noodzaak is, of je m.a.w. niet ook gewoon de lokale servertijd tot norm kan verheffen, en mutatis mutandis elke timestamp kan converteren naar de lokale timezone van de gebruiker. Ik denk echter dat je dan ook hetzelfde vraagstuk krijgt met DST.

Tijdzones zijn ten opzichte van UTC. Daarmee lijkt UTC het aangewezen uitgangspunt.

Link to comment

Dat ligt aan de definitie die je hanteert, Get ( CurrentTimeUTCMilliseconds ) is het aantal verstreken milliseconden (getal) sinds "01-01-0001 0:00:00,0", dus als zodanig is het inderdaad een (verstreken) tijd.

FileMaker slaat tijdstempels, data (datums in Nieuwspraak) en tijden intern op als getallen en daarom kan je de UTC gemakkelijk als tijdstempel, datum of tijd noteren:

Let ( [     
    UTC = get ( CurrentTimeUTCMilliseconds )
] ;     
    List ( 
        GetAsTimestamp ( UTC / 1000 ) ; 
        GetAsDate ( Floor ( UTC / 86400000 ) ) ; 
        GetAsTime ( UTC / 1000 ) 
    )
)

 

Link to comment

Dank Menno, als ik een beetje had opgelet had ik kunnen zien dat de UTC functie inderdaad niet een 'dagtijd' oplevert. Dus UTC levert dus toch echt een volwaardige datetimestamp.

Vind het jammer dat Get ( CurrentTimeUTCMilliseconds ) geen variant heeft die op de host klok gebaseerd is, nu eigenlijk wel duidelijk is dat lokale timestamps uit den boze zijn als tijd-ertoe-doet in een multi-timezone systeem. 

Een calculatie/CF als hieronder zou de server UTC-timestamp kunnen leveren..

Let ( 
[ hostTS = Get (TijdstempelHuidigeHost)
; localUTC = Floor ( Get ( HuidigeTijdUTCMilliseconden ) / 1000 )
; delta = GetAsNumber ( hostTS - localUTC )
];

hostTS - delta

)

Een tweede uitdaging is de uitbreiding van jouw CF: het converteren van een willekeurig UTC naar een lokale tijd, waarbij je uitgaat van tijdzone, wel/geen DST en zo ja, is deze actief op het moment van de gegeven UTC.

Ik vraag me af wat de performance implicaties gaan zijn als je deze grappen echt implementeert.

Link to comment

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...