SlideShare une entreprise Scribd logo
1  sur  88
Télécharger pour lire hors ligne
Ne perdez plus votre
Temps avec les Dates
#RetourAuxSources
Frédéric CAMBLOR
4SH France
@fcamblor
GDG Tours
2019-06-19T19:00:00+02:00
#DateTimeBasics
Avertissement
Cette présentation n’aborde pas vraiment des technologies à la mode.

Pire, vous risquez de ressortir de cette présentation avec moins de certitudes
que vous n’en aviez en arrivant.
Acceptez-vous de poursuivre cette présentation sur les Dates et le Temps ?
Si vous voulez savoir comment déployer dans la Blockchain des Microservices
Kotlin codés avec Quarkus sur une plateforme Kubernetes Native dans une
image Docker basée sur GraalVM,il est encore temps de partir :-)
Ne perdez plus votre
Temps avec les Dates
#RetourAuxSources
Frédéric CAMBLOR
4SH France
@fcamblor
GDG Tours
2019-06-19T19:00:00+02:00
#DateTimeBasics
🤔
Qui n’a jamais eu de soucis avec le Temps
(en général) ?
Apple
http://bit.ly/iphonote-bug-dst-apple
Microsoft
http://bit.ly/cnet-new-years-microsoft
Twitter
http://bit.ly/programmes-twitter-bug-2015
Y2K Bug anyone ?
https://en.wikipedia.org/wiki/Year_2000_problem
Remontons le Temps...
Au Zenith,il est 12:00
PhotobyPatxiMartin
L'arrivée des heures standards (1847-1972)
La seconde comme unité de temps
• Unité du système international
• Confiance dans sa durée
• Élément physique régulier & mesurable
🤔
9,192,631,770 ?
Temps atomique international (TAI)
PhotobyDnn87onWikimedia
Coordinated Universal Time (UTC)
• Basé sur le TAI
• Agnostic de la géographie / géopolitique
• Stable/Continu dans le temps

Pas d'heure d'été/hiver
• EPOCH : 1970-01-01T00:00:00Z
EPOCHs
https://fr.wikipedia.org/wiki/Epoch
Leap Seconds
• Variable d'ajustement entre UT1& TAI
• Annoncée ~6mois à l'avance
• Positionnée fin juin/décembre
• 37 Leap Seconds depuis l'EPOCH

au 2019-06-19T19:00:00+02:00
NTP (NetworkTime Protocol)
https://en.wikipedia.org/wiki/Network_Time_Protocol
Perspective
On voit souvent les Dates/Heures depuis des angles différents
Timestamps
Unix milliseconds : 1548954000000
Unix : 1548954000
⚠ à l'overflow le 2038-01-19T03:14:07
Datetime ISO 8601 / RFC 3339
https://www.w3.org/TR/NOTE-datetime
2019-01-31T18:00:00+01:00
2019-01-31T17:00:00Z
Date & Time"Local"
Jeudi 31 Janvier 2019, 06:00 PM
2019-01-31T18:00:00
2019-01-31
Les TIMEZONES
Timezone
Europe/Paris
America/New_York

Antarctica/South_Pole
...
2019-01-31T17:00:00Z
2019-01-31T18:00:00+01:00
2019-01-31T12:00:00-05:00
...
Timezone offset
⚠ Notions très différentes !
Standard World Timezone Offsets
https://en.wikipedia.org/wiki/Time_zone
❌ Timezone => Timezone offset
moment.tz("2018-01-29 18:00", "Europe/Paris").format()
=> 2018-01-29T18:00:00+01:00
moment.tz("2018-06-29 18:00", "Europe/Paris").format()
=> 2018-06-29T18:00:00+02:00
✅ Timezone + Datetime + Tz Table
=> Timezone offset
TIMEZONES: Points clef
• TZ définit des offsets par rapport à UTC
• Ils varient de -12:00 à +14:00
• Les offsets sont "généralement" d'1h
• Offsets variables par timezone (DST)
• TZ Tables : IANA & Windows TimeZones
Internet Assigned Numbers Authority (IANA) for Europe
https://github.com/eggert/tz/blob/master/europe
🤔
Comment mon système se met-il à jour ?
En JAVA c'est packagé dans les JRE + TZUpdater tool
http://bit.ly/JRE-IANA
Pour MySQL il faut le faire à la main
http://bit.ly/mysql-tzdata
Pour NodeJS il faut le gérer à la main
https://www.npmjs.com/package/geo-tz
tldr; posez-vous la question !
L'OS peut aussi mettre à disposition ces tables
TZ Data: Points clef
• Très lié à la géopolitique
• Les règles changent, régulièrement
• Les règles changent, subitement
• Europe : vers une abolition de DST
• Ne rien considérer comme acquis

⚠ ⚠ ⚠ aux dates dans le futur
Lorsque vous stockez une Date+Heure dans le futur :
Stockez l'heure locale & la timezone
de l'utilisateur à l'origine de cette Date
Vous pourrez corriger le problème
(à condition de le détecter)
https://codeblog.jonskeet.uk/2019/03/27/storing-utc-is-not-a-silver-bullet/
Daylight Saving Time (DST)
tzDate("2019-03-31T01:10:00", "Europe/Paris")
=> 2019-03-31T01:10:00+01:00
Certaines heures locales n'existent pas (Local Time Gap)
02:00 -> 03:00 pour Europe/Paris
tzDate("2019-03-31T01:10:00", "Europe/Paris").add(1, 'hour')
=> 2019-03-31T03:10:00+02:00
tzDate("2019-03-31T02:10:00", "Europe/Paris")
=> 2019-03-31T03:10:00+02:00
Daylight Saving Time (DST)
tzDate("2019-10-27T02:10:00", "Europe/Paris")
=> 2019-10-27T02:10:00+02:00
Certaines heures locales existent 2 fois
02:00 -> 03:00 pour Europe/Paris
tzDate("2019-10-27T02:10:00", "Europe/Paris").add(1, 'hour')
=> 2019-10-27T02:10:00+01:00
La date/heure DST varie en fonction de la timezone
http://bit.ly/dst-diffs
Fausse bonne idée
"Notre batch de facturation passe tous les jours à 2h30
du matin (heure locale),car il s'agit du moment où le
système est le moins sollicité"
🤦 &
🤔
DST varie-t-il *toujours* d'1h ?
Peut-on avoir plus de 2 shifts par an ?
👍*
👍
Explorons un certain nombre
d'idées reçues...
"Il y a 24h dans une journée
et 365 jours dans une année"
#FakeNews
(facile!)
Années bissextiles
Duration.between(
ZonedDateTime.parse("2016-01-01T00:00:00+01:00[Europe/Paris]"),
ZonedDateTime.parse("2017-01-01T00:00:00+01:00[Europe/Paris]")
).toDays()
=> 366
• Tous les 4 ans
• Sauf années séculaires (tous les 100 ans)
• Sauf années multiples de 400
2000 était bissextile,mais 2100 ne le sera pas.
Daylight Saving Time
Duration.between(
ZDTFactory("2018-03-25T00:00:00", "Europe/Paris"),
ZDTFactory("2018-03-26T00:00:00", "Europe/Paris")
).toHours()
=> 23
Duration.between(
ZDTFactory("2018-10-28T00:00:00", "Europe/Paris"),
ZDTFactory("2018-10-29T00:00:00", "Europe/Paris")
).toHours()
=> 25
🤔
Qui a raison ?
public ZonedDateTime calculateNextThingAfter(ZonedDateTime d) {
return d.plusDays(1);
}
public ZonedDateTime calculateNextThingAfter(ZonedDateTime d) {
return d.plusHours(24);
}
#scaleMatters
Fun fact : aucun 2011-12-30 (Friday) aux Samoa
https://www.timeanddate.com/news/time/samoa-dateline.html
"Comparer des dates,c'est facile !"
#FakeNews
🤔
Mais où est le problème ?
boolean datesAreEqual(ZonedDateTime d1, ZonedDateTime d2) {
return Objects.equals(d1, d2);
}
ZonedDateTime.parse("2018-03-25T00:00:00+01:00[Europe/Berlin]")
.equals(ZonedDateTime.parse("2018-03-25T00:00:00+01:00[Europe/Paris]"))
=> false
ZonedDateTime.parse("2018-03-25T00:00:00+01:00[Europe/Berlin]")
.isEqual(ZonedDateTime.parse("2018-03-25T00:00:00+01:00[Europe/Paris]"))
=> true
Égalité vs Identité
"L'objet Date en Javascript,
c'est de la balle !"
#FakeNews
Format non ISO => date Locale | Format ISO => date UTC
https://twitter.com/seldo/status/1091861205260500992
D'autres blagues
• Les mois commencent à 0

On a trouvé d'où vient le "Java" de "Javascript" !
• Aucune gestion des timezones / internationalisation
• La gestion des "anciens" timezone offsets est (complètement) broken

... chez tout le monde (Chrome, Firefox, IE, Safari, Node)
https://codeofmatt.com/javascript-date-type-is-horribly-broken/
Utilisez une librairie
• momentjs + moment-timezone
• dayjs / Luxon
• date-fns
🤔
#MomentJS #FunFacts
De quelle Locale parle-t-on ?
moment().add(4, 'hours').locale('tlh').fromNow()
=> loS rep pIq
🖖
Bon,on devrait avoir fait le tour
de toutes les règles bizarres maintenant...
Numéros de semaine
moment("2017-01-02T00:00:00+01:00").format("GGGG-WW")
=> 2017-01
moment("2016-01-02T00:00:00+01:00").format("GGGG-WW")
=> 2015-53
Le premier jour de la semaine peut varier...
https://en.wikipedia.org/wiki/Week
La notion de Chronology
• ISO 8601 = Calendrier Grégorien de facto
• Il en existe plein d'autres : Julien, Ethiopien, Bouddhiste, Islamiste, Copte...
• Règles différentes sur l'année de départ
• Règles différentes sur les années bissextiles
• Répartition différente des jours dans les mois
AM / PM (sacrés British)
•12 AM (=00:00) < 1 AM (=01:00)
•Notation ambigüe à l'oral
if(hour === 0) {
ampm = 'AM'; hour = 12;
} else if(hour < 12) {
ampm = 'AM'; hour = hour;
} else if(hour == 12) {
ampm = 'PM'; hour = 12;
} else {
ampm = 'PM'; hour -= 12;
}
Quelques bonnes pratiques
issues de la vie réelle
Les serveurs doivent être en UTC
•Timezone de l'OS

•Timezone de la DB

Il n'est pas tout le temps possible de la changer
•Timezone de votre serveur d'App
sudo timedatectl set-timezone UTC
# Or : sudo dpkg-reconfigure tzdata
-Duser.timezone=UTC
L'intervalle de temps implicite
👍 GET /messages?after=2019-02-09T00:00:00+01:00&before=2019-02-09T23:59:59+01:00
👎 GET /messages?date=2019-02-09
👋 GET /messages?date=2019-02-09&tz=Europe/Paris
L'intervalle de temps implicite
// Assumes client and server timezones are the same
SELECT * FROM messages WHERE published_on = '2019-02-09';
👍 Expected👎 Result
👎 GET /messages?date=2019-02-09
L'intervalle de temps implicite
1/ Convert date to date midnight using Europe/Paris Timezone
2019-02-09 => 2019-02-09T00:00:00+01:00
👍 Expected
👋 GET /messages?date=2019-02-09&tz=Europe/Paris
👎 Result
# Swap 2 & 3 for expected result !
2/ Convert to UTC
=> 2019-02-08T23:00:00Z
3/ Transform to Range using startOf/endOf day
=> [ 2019-02-08T00:00:00Z, 2019-02-08T23:59:59Z ]
L'intervalle de temps implicite
1/ Convert date to date midnight using Europe/Paris Timezone
2019-02-09 => 2019-02-09T00:00:00+01:00
2/ Transform to Range using startOf/endOf day
=> [ 2019-02-09T00:00:00+01:00, 2019-02-09T23:59:59+01:00 ]
3/ Convert to UTC
=> [ 2019-02-08T23:00:00Z, 2019-02-09T22:59:59Z ]
👍 Expected
👋 GET /messages?date=2019-02-09&tz=Europe/Paris
👍 Result
L'intervalle de temps implicite
// Nothing fancy happening serverside since we're
// working with timestamps
SELECT * FROM messages WHERE published_on
BETWEEN '2019-02-08T23:00:00Z' AND '2019-02-09T23:00:00Z' ;
👍 Expected👍 Result
👍 GET /messages?start=2019-02-09T00:00:00+01:00

&end=2019-02-09T23:59:59+01:00
Date search Patterns
• Dans 99% des cas vous allez faire des recherches sur des
intervalles de temps

• Faites (si possible) les conversions coté appelant* (client)
• Stockez* & Recherchez vos datetime en UTC
Attention aux"Heures locales"
[On est le 08/03 à Bordeaux]
"Le magasin ouvre à 9h du matin les jours ouvrés"
"J'aimerais planifier une réunion à 15h (Europe/Paris) tous les lundi"
Heure sans Date attachée
Attention aux"Heures locales"
[On est le 08/03 à Bordeaux]
"J'aimerais planifier une réunion à 15h (Europe/Paris) tous les lundi"
1/ "Le dernier lundi d'avril" 

=> 2019-04-29 (Date Locale)
2/ Ajout de la composante heure + timezone offset

=> 2019-04-29T15:00:00+02:00

Attention aux cas exceptionnels !
👍 "localTime": "15:00 [Europe/Paris]"
3/ Décalage dans une tz cible (ex: America/New_York)

=> 2019-04-29T09:00:00-04:00
Time-only Patterns
• Stocker la Timezone de l'utilisateur ayant saisi l'heure

• Évitez de stocker votre Time dans un DateTime

🙈 1970-01-01T15:35:00Z

• Mettez à disposition la Timezone cible
Date-only Patterns
• Utilisez une structure de données adhoc

• Évitez de stocker votre Date dans un DateTime 

🙈 1732-02-22T00:00:00Z

• Si vous êtes sûr de la Timezone, stockez-la
Les"Local Datetime"
Une DateTime sans Timezone
ne peut pas être "identifiée" chronologiquement
À éviter,absolument !
http://blog.schauderhaft.de/2018/03/14/dont-use-localdatetime/
Pour conclure...
Bien considérer toutes les perspectives
Bien faire la distinction entre
Heure Standard et Heure Locale
Les Timezones sont changeantes,
(potentiellement) rapidement
Mettez régulièrement à jour vos tzdata
Évitez de stocker des dates dans le futur
Si vous n'avez pas le choix stockez l'heure
locale et la Timezone
Lors d'une opération sur les Dates/Heures,
utilisez la bonne échelle de temps
Ne faites pas confiance à l'objet Date
en Javascript
Stockez et faites vos recherches en UTC
Interrogez-vous lorsque vous faites des
recherches sur des dates uniques (sans range)
Ne prenez rien comme acquis
Questionnez-vous
...Tout le Temps
Des questions ?

Contenu connexe

Similaire à Back to basics - Ne perdez plus votre Temps avec les Dates - GDG Tours Edition

rt-intro.pdf
rt-intro.pdfrt-intro.pdf
rt-intro.pdfSaid Ech
 
Monitoring d'un compteur EDF avec node.js @bdx.io
Monitoring d'un compteur EDF avec node.js @bdx.ioMonitoring d'un compteur EDF avec node.js @bdx.io
Monitoring d'un compteur EDF avec node.js @bdx.iolaurenthuet
 
Pourquoi Terraform n'est pas le bon outil pour les déploiements automatisés d...
Pourquoi Terraform n'est pas le bon outil pour les déploiements automatisés d...Pourquoi Terraform n'est pas le bon outil pour les déploiements automatisés d...
Pourquoi Terraform n'est pas le bon outil pour les déploiements automatisés d...Duyhai Doan
 
Modern DevOps - kill the bottleneck (part 2/2)
Modern DevOps - kill the bottleneck (part 2/2)Modern DevOps - kill the bottleneck (part 2/2)
Modern DevOps - kill the bottleneck (part 2/2)Loic Ortola
 
Core web vitals pour unifier UX et SEO - Stephane Rios - SEO Camp'us paris 2020
Core web vitals pour unifier UX et SEO - Stephane Rios - SEO Camp'us paris 2020Core web vitals pour unifier UX et SEO - Stephane Rios - SEO Camp'us paris 2020
Core web vitals pour unifier UX et SEO - Stephane Rios - SEO Camp'us paris 2020SEO CAMP
 
Monitoring applicatif : Pourquoi et comment ?
Monitoring applicatif : Pourquoi et comment ?Monitoring applicatif : Pourquoi et comment ?
Monitoring applicatif : Pourquoi et comment ?Kenny Dits
 
NFS, MPI, Programmation Sérial & Parallèle avec Condor Scénarios et Simulatio...
NFS, MPI, Programmation Sérial & Parallèle avec Condor Scénarios et Simulatio...NFS, MPI, Programmation Sérial & Parallèle avec Condor Scénarios et Simulatio...
NFS, MPI, Programmation Sérial & Parallèle avec Condor Scénarios et Simulatio...Ayoub Rouzi
 
meetup - Workflow complet de CI/CD pour les geeks avec gitlab et kubernetes
meetup - Workflow complet de CI/CD pour les geeks avec gitlab et kubernetesmeetup - Workflow complet de CI/CD pour les geeks avec gitlab et kubernetes
meetup - Workflow complet de CI/CD pour les geeks avec gitlab et kubernetesFrederic Leger
 
Comment développer un serveur métier en python/C++
Comment développer un serveur métier en python/C++Comment développer un serveur métier en python/C++
Comment développer un serveur métier en python/C++cppfrug
 
Track 2 - Atelier 3 - Comment Ysance met le cloud au service du digital avec ...
Track 2 - Atelier 3 - Comment Ysance met le cloud au service du digital avec ...Track 2 - Atelier 3 - Comment Ysance met le cloud au service du digital avec ...
Track 2 - Atelier 3 - Comment Ysance met le cloud au service du digital avec ...Amazon Web Services
 
OVH Summit 2016 - Map as a Service by Löic Ortola
OVH Summit 2016 - Map as a Service by Löic OrtolaOVH Summit 2016 - Map as a Service by Löic Ortola
OVH Summit 2016 - Map as a Service by Löic OrtolaJawg Maps
 
Une plateforme moderne pour le groupe SIPA/Ouest-France 
Une plateforme moderne pour le groupe SIPA/Ouest-France Une plateforme moderne pour le groupe SIPA/Ouest-France 
Une plateforme moderne pour le groupe SIPA/Ouest-France François-Guillaume Ribreau
 
Core Web Vitals, les indicateurs de vitesse qui réconcilient UX et SEO
Core Web Vitals, les indicateurs de vitesse qui réconcilient UX et SEOCore Web Vitals, les indicateurs de vitesse qui réconcilient UX et SEO
Core Web Vitals, les indicateurs de vitesse qui réconcilient UX et SEOWeLoveSEO
 
Stream processing et SQL
Stream processing et SQLStream processing et SQL
Stream processing et SQLBruno Bonnin
 
C++ 11 - Tech Days 2014 in Paris
C++ 11 - Tech Days 2014 in ParisC++ 11 - Tech Days 2014 in Paris
C++ 11 - Tech Days 2014 in Parischristophep21
 
Bonnes pratiques pour apprivoiser le C++11 avec Visual C++
Bonnes pratiques pour apprivoiser le C++11 avec Visual C++Bonnes pratiques pour apprivoiser le C++11 avec Visual C++
Bonnes pratiques pour apprivoiser le C++11 avec Visual C++Microsoft
 
Soirée webperf du 29 nov 2010 - Latence et CDN
Soirée webperf du 29 nov 2010 - Latence et CDNSoirée webperf du 29 nov 2010 - Latence et CDN
Soirée webperf du 29 nov 2010 - Latence et CDNEric D.
 
Le Bulletin Azure épisode 1
Le Bulletin Azure épisode 1Le Bulletin Azure épisode 1
Le Bulletin Azure épisode 1benjguin
 

Similaire à Back to basics - Ne perdez plus votre Temps avec les Dates - GDG Tours Edition (20)

rt-intro.pdf
rt-intro.pdfrt-intro.pdf
rt-intro.pdf
 
Monitoring d'un compteur EDF avec node.js @bdx.io
Monitoring d'un compteur EDF avec node.js @bdx.ioMonitoring d'un compteur EDF avec node.js @bdx.io
Monitoring d'un compteur EDF avec node.js @bdx.io
 
Pourquoi Terraform n'est pas le bon outil pour les déploiements automatisés d...
Pourquoi Terraform n'est pas le bon outil pour les déploiements automatisés d...Pourquoi Terraform n'est pas le bon outil pour les déploiements automatisés d...
Pourquoi Terraform n'est pas le bon outil pour les déploiements automatisés d...
 
Modern DevOps - kill the bottleneck (part 2/2)
Modern DevOps - kill the bottleneck (part 2/2)Modern DevOps - kill the bottleneck (part 2/2)
Modern DevOps - kill the bottleneck (part 2/2)
 
Core web vitals pour unifier UX et SEO - Stephane Rios - SEO Camp'us paris 2020
Core web vitals pour unifier UX et SEO - Stephane Rios - SEO Camp'us paris 2020Core web vitals pour unifier UX et SEO - Stephane Rios - SEO Camp'us paris 2020
Core web vitals pour unifier UX et SEO - Stephane Rios - SEO Camp'us paris 2020
 
Monitoring applicatif : Pourquoi et comment ?
Monitoring applicatif : Pourquoi et comment ?Monitoring applicatif : Pourquoi et comment ?
Monitoring applicatif : Pourquoi et comment ?
 
NFS, MPI, Programmation Sérial & Parallèle avec Condor Scénarios et Simulatio...
NFS, MPI, Programmation Sérial & Parallèle avec Condor Scénarios et Simulatio...NFS, MPI, Programmation Sérial & Parallèle avec Condor Scénarios et Simulatio...
NFS, MPI, Programmation Sérial & Parallèle avec Condor Scénarios et Simulatio...
 
meetup - Workflow complet de CI/CD pour les geeks avec gitlab et kubernetes
meetup - Workflow complet de CI/CD pour les geeks avec gitlab et kubernetesmeetup - Workflow complet de CI/CD pour les geeks avec gitlab et kubernetes
meetup - Workflow complet de CI/CD pour les geeks avec gitlab et kubernetes
 
Comment développer un serveur métier en python/C++
Comment développer un serveur métier en python/C++Comment développer un serveur métier en python/C++
Comment développer un serveur métier en python/C++
 
Track 2 - Atelier 3 - Comment Ysance met le cloud au service du digital avec ...
Track 2 - Atelier 3 - Comment Ysance met le cloud au service du digital avec ...Track 2 - Atelier 3 - Comment Ysance met le cloud au service du digital avec ...
Track 2 - Atelier 3 - Comment Ysance met le cloud au service du digital avec ...
 
Laugaudin UFR12
Laugaudin UFR12Laugaudin UFR12
Laugaudin UFR12
 
OVH Summit 2016 - Map as a Service by Löic Ortola
OVH Summit 2016 - Map as a Service by Löic OrtolaOVH Summit 2016 - Map as a Service by Löic Ortola
OVH Summit 2016 - Map as a Service by Löic Ortola
 
Une plateforme moderne pour le groupe SIPA/Ouest-France 
Une plateforme moderne pour le groupe SIPA/Ouest-France Une plateforme moderne pour le groupe SIPA/Ouest-France 
Une plateforme moderne pour le groupe SIPA/Ouest-France 
 
Core Web Vitals, les indicateurs de vitesse qui réconcilient UX et SEO
Core Web Vitals, les indicateurs de vitesse qui réconcilient UX et SEOCore Web Vitals, les indicateurs de vitesse qui réconcilient UX et SEO
Core Web Vitals, les indicateurs de vitesse qui réconcilient UX et SEO
 
Stream processing et SQL
Stream processing et SQLStream processing et SQL
Stream processing et SQL
 
C++ 11 - Tech Days 2014 in Paris
C++ 11 - Tech Days 2014 in ParisC++ 11 - Tech Days 2014 in Paris
C++ 11 - Tech Days 2014 in Paris
 
Bonnes pratiques pour apprivoiser le C++11 avec Visual C++
Bonnes pratiques pour apprivoiser le C++11 avec Visual C++Bonnes pratiques pour apprivoiser le C++11 avec Visual C++
Bonnes pratiques pour apprivoiser le C++11 avec Visual C++
 
Soirée webperf du 29 nov 2010 - Latence et CDN
Soirée webperf du 29 nov 2010 - Latence et CDNSoirée webperf du 29 nov 2010 - Latence et CDN
Soirée webperf du 29 nov 2010 - Latence et CDN
 
TypeScript
TypeScriptTypeScript
TypeScript
 
Le Bulletin Azure épisode 1
Le Bulletin Azure épisode 1Le Bulletin Azure épisode 1
Le Bulletin Azure épisode 1
 

Back to basics - Ne perdez plus votre Temps avec les Dates - GDG Tours Edition