diff --git a/app/models/communication/website/agenda/event.rb b/app/models/communication/website/agenda/event.rb
index a482b9fc91be146ed84a46c8c6ca1297c01dc95c..30977fc2b6791e20cb6f142406f2f7fbbd5bf189 100644
--- a/app/models/communication/website/agenda/event.rb
+++ b/app/models/communication/website/agenda/event.rb
@@ -46,11 +46,13 @@ class Communication::Website::Agenda::Event < ApplicationRecord
   include Sanitizable
   include WithAccessibility
   include WithBlobs
+  include WithCal
   include WithDuplication
   include WithFeaturedImage
   include WithMenuItemTarget
   include WithPermalink
   include WithSlug
+  include WithTime
   include WithTranslations
   include WithTree
   include WithUniversity
@@ -74,49 +76,6 @@ class Communication::Website::Agenda::Event < ApplicationRecord
 
   scope :for_category, -> (category_id) { joins(:categories).where(communication_website_categories: { id: category_id }).distinct }
 
-  scope :future, -> { where('from_day > :today', today: Date.today).ordered_asc }
-  scope :future_or_current, -> { where('from_day >= :today', today: Date.today).ordered_asc }
-  scope :current, -> { where('(from_day <= :today AND to_day IS NULL) OR (from_day <= :today AND to_day >= :today)', today: Date.today).ordered_asc }
-  scope :archive, -> { where('to_day < :today', today: Date.today).ordered_desc }
-  scope :past, -> { archive }
-
-  validates_presence_of :from_day, :title
-  validate :to_day_after_from_day, :to_hour_after_from_hour_on_same_day
-
-  STATUS_FUTURE = 'future'
-  STATUS_CURRENT = 'current'
-  STATUS_ARCHIVE = 'archive'
-
-  def status
-    if future?
-      STATUS_FUTURE
-    elsif current?
-      STATUS_CURRENT
-    else
-      STATUS_ARCHIVE
-    end
-  end
-
-  def future?
-    from_day > Date.today
-  end
-
-  def current?
-    to_day.present? ? (Date.today >= from_day && Date.today <= to_day)
-                    : from_day <= Date.today # Les événements sans date de fin restent actifs
-  end
-
-  def archive?
-    to_day.present? ? to_day < Date.today
-                    : false # Les événements sans date de fin restent actifs
-  end
-
-  # Un événement demain aura une distance de 1, comme un événement hier
-  # On utilise cette info pour classer les événements à venir dans un sens et les archives dans l'autre
-  def distance_in_days
-    (Date.today - from_day).to_i.abs
-  end
-
   def git_path(website)
     return unless website.id == communication_website_id && published
     path = "#{git_path_content_prefix(website)}events/"
@@ -148,69 +107,16 @@ class Communication::Website::Agenda::Event < ApplicationRecord
     "#{Static.remove_trailing_slash website.url}#{Static.clean_path current_permalink_in_website(website).path}"
   end
 
-  def cal
-    @cal ||= AddToCalendar::URLs.new(
-      start_datetime: from_time, 
-      end_datetime: to_time,
-      timezone: 'Europe/Paris',
-      title: "#{title} #{subtitle}",
-      url: url,
-      description: summary,
-      all_day: (from_hour.nil? && to_hour.nil?)
-    )
-  end
-
   def to_s
     "#{title}"
   end
 
   protected
 
-  def from_time
-    from_hour.nil?  ? from_day.to_time
-                    : date_and_time(from_day, from_hour)
-  end
-
-  def to_time
-    if to_day.nil? && to_hour.nil?
-      # Pas de fin
-      nil
-    elsif to_day.nil? && to_hour.present?
-      # Heure de fin sans jour de fin, donc on se base sur le jour de début
-      date_and_time(from_day, to_hour)
-    elsif to_day.present? && to_hour.nil?
-      # Jour de fin seul
-      to_day.to_time
-    elsif to_day.present? && to_hour.nil?
-      # Jour et heure de fin
-      date_and_time(to_day, to_hour)
-    end
-  end
-
-  def date_and_time(date, time)
-    # FIXME la timezone est Europe/Paris pour tout
-    Time.new  date.year,
-              date.month,
-              date.day,
-              time.hour,
-              time.min,
-              time.sec,
-              Time.zone
-  end
-
   def check_accessibility
     accessibility_merge_array blocks
   end
 
-  def to_day_after_from_day
-    errors.add(:to_day, :too_soon) if to_day.present? && to_day < from_day
-  end
-
-  def to_hour_after_from_hour_on_same_day
-    return if from_day != to_day
-    errors.add(:to_hour, :too_soon) if to_hour.present? && from_hour.present? && to_hour < from_hour
-  end
-
   def explicit_blob_ids
     super.concat [featured_image&.blob_id]
   end
diff --git a/app/models/communication/website/agenda/event/with_cal.rb b/app/models/communication/website/agenda/event/with_cal.rb
new file mode 100644
index 0000000000000000000000000000000000000000..450d395dc9dff051fc23e4991683a06d99bd52cc
--- /dev/null
+++ b/app/models/communication/website/agenda/event/with_cal.rb
@@ -0,0 +1,58 @@
+module Communication::Website::Agenda::Event::WithCal
+  extend ActiveSupport::Concern
+
+  def cal
+    @cal ||= AddToCalendar::URLs.new(
+      start_datetime: cal_from_time, 
+      end_datetime: cal_to_time,
+      timezone: timezone.name,
+      all_day: cal_all_day,
+      title: "#{title} #{subtitle}",
+      url: url,
+      description: summary
+    )
+  end
+
+  protected
+
+  def cal_from_time
+    from_hour.nil?  ? from_day.to_time
+                    : date_and_time(from_day, from_hour)
+  end
+
+  def cal_to_time
+    to_day.nil? ? cal_to_time_with_no_end_day
+                : cal_to_time_with_end_day
+  end
+
+  def cal_all_day
+    from_hour.nil? && to_hour.nil?
+  end
+
+  # Ce cas n'est plus possible depuis la résolution #1386
+  def cal_to_time_with_no_end_day
+    to_hour.nil?  ? nil # Pas de fin
+                  : date_and_time(from_day, to_hour) # Heure de fin sans jour de fin, donc on se base sur le jour de début
+  end
+
+  def cal_to_time_with_end_day
+    to_hour.nil?  ? to_day.to_time + 1.hour # Jour de fin seul, on ajoute 1 heure pour éviter les événements sans durée
+                  : date_and_time(to_day, to_hour) # Jour et heure de fin
+  end
+
+  def timezone
+    # FIXME la timezone est Europe/Paris pour tout
+    Time.zone
+  end
+
+  def date_and_time(date, time)
+    Time.new  date.year,
+              date.month,
+              date.day,
+              time.hour,
+              time.min,
+              time.sec,
+              timezone
+  end
+
+end
diff --git a/app/models/communication/website/agenda/event/with_time.rb b/app/models/communication/website/agenda/event/with_time.rb
new file mode 100644
index 0000000000000000000000000000000000000000..5d0c09866ff82ce642c2b378c42d7090cb179d09
--- /dev/null
+++ b/app/models/communication/website/agenda/event/with_time.rb
@@ -0,0 +1,69 @@
+module Communication::Website::Agenda::Event::WithTime
+  extend ActiveSupport::Concern
+
+  included do
+    STATUS_FUTURE = 'future'
+    STATUS_CURRENT = 'current'
+    STATUS_ARCHIVE = 'archive'
+    
+    scope :future, -> { where('from_day > :today', today: Date.today).ordered_asc }
+    scope :future_or_current, -> { where('from_day >= :today', today: Date.today).ordered_asc }
+    scope :current, -> { where('(from_day <= :today AND to_day IS NULL) OR (from_day <= :today AND to_day >= :today)', today: Date.today).ordered_asc }
+    scope :archive, -> { where('to_day < :today', today: Date.today).ordered_desc }
+    scope :past, -> { archive }
+
+    before_validation :set_to_day
+
+    validates_presence_of :from_day, :title
+    validate :to_day_after_from_day, :to_hour_after_from_hour_on_same_day
+  end
+
+  def status
+    if future?
+      STATUS_FUTURE
+    elsif current?
+      STATUS_CURRENT
+    else
+      STATUS_ARCHIVE
+    end
+  end
+
+  def future?
+    from_day > Date.today
+  end
+
+  def current?
+    to_day.present? ? (Date.today >= from_day && Date.today <= to_day)
+                    : from_day <= Date.today # Les événements sans date de fin restent actifs
+  end
+
+  def archive?
+    to_day.present? ? to_day < Date.today
+                    : false # Les événements sans date de fin restent actifs
+  end
+
+  def same_day?
+    from_day == to_day
+  end
+
+  # Un événement demain aura une distance de 1, comme un événement hier
+  # On utilise cette info pour classer les événements à venir dans un sens et les archives dans l'autre
+  def distance_in_days
+    (Date.today - from_day).to_i.abs
+  end
+  
+  protected
+
+  def set_to_day
+    self.to_day = self.from_day if self.to_day.nil?
+  end
+
+  def to_day_after_from_day
+    errors.add(:to_day, :too_soon) if to_day.present? && to_day < from_day
+  end
+
+  def to_hour_after_from_hour_on_same_day
+    return if from_day != to_day
+    errors.add(:to_hour, :too_soon) if to_hour.present? && from_hour.present? && to_hour < from_hour
+  end
+end
diff --git a/app/views/admin/communication/websites/agenda/events/_dates.html.erb b/app/views/admin/communication/websites/agenda/events/_dates.html.erb
index 870e21eb40e032eafeab9b7a85979a0a9a48814c..5df299ee030a068ece7e25fbfa992e47793dac7e 100644
--- a/app/views/admin/communication/websites/agenda/events/_dates.html.erb
+++ b/app/views/admin/communication/websites/agenda/events/_dates.html.erb
@@ -1,9 +1,23 @@
-<i class="fas fa-play-circle"></i>
-<%= l(event.from_day) %>
-<%= l(event.from_hour, format: :time_only) if event.from_hour %>
-<% if event.to_day %>
-  <br>
-  <i class="fas fa-stop-circle"></i>
-  <%= l(event.to_day) %>
-  <%= l(event.to_hour, format: :time_only) if event.to_hour %>
+<%
+detailed = local_assigns.dig(:detailed)
+day_format = detailed ? :full
+                      : :default
+%>
+<% if event.same_day? %>
+  <%= l(event.from_day, format: day_format).upcase_first %>
+  <% if event.from_hour %>
+    <br>
+    <%= l(event.from_hour, format: :time_only) %>
+    <% if event.to_hour %>
+      - <%= l(event.to_hour, format: :time_only) %>
+    <% end %>
+  <% end %>
+<% else %>
+  <%= l(event.from_day, format: day_format).upcase_first %>
+  <%= l(event.from_hour, format: :time_only) if event.from_hour %>
+  <% if event.to_day %>
+    <br>
+    <%= l(event.to_day, format: day_format).upcase_first %>
+    <%= l(event.to_hour, format: :time_only) if event.to_hour %>
+  <% end %>
 <% end %>
\ No newline at end of file
diff --git a/app/views/admin/communication/websites/agenda/events/_dates_static.html.erb b/app/views/admin/communication/websites/agenda/events/_dates_static.html.erb
index 04fa585b16fbbd66b4389714347884a51282561b..703d8eb353d11ae8b7f5e76b76a251ee4f6c9b8a 100644
--- a/app/views/admin/communication/websites/agenda/events/_dates_static.html.erb
+++ b/app/views/admin/communication/websites/agenda/events/_dates_static.html.erb
@@ -26,8 +26,8 @@ indentation = '  ' * depth
 <%= indentation %>    hour: <%= event.to_hour.strftime "%H:%M" %>
 <% end %>
 <%= indentation %>  add_to_calendar:
-<%= indentation %>    google: "<%= event.cal.google_url %>"
-<%= indentation %>    yahoo: "<%= event.cal.yahoo_url %>"
-<%= indentation %>    office: "<%= event.cal.office365_url %>"
-<%= indentation %>    outlook: "<%= event.cal.outlook_com_url %>"
-<%= indentation %>    ical: "<%= event.cal.ical_url %>"
+<%= indentation %>    google: "<%= event.cal.google_url.html_safe %>"
+<%= indentation %>    yahoo: "<%= event.cal.yahoo_url.html_safe %>"
+<%= indentation %>    office: "<%= event.cal.office365_url.html_safe %>"
+<%= indentation %>    outlook: "<%= event.cal.outlook_com_url.html_safe %>"
+<%= indentation %>    ical: "<%= event.cal.ical_url.html_safe %>"
diff --git a/app/views/admin/communication/websites/agenda/events/show.html.erb b/app/views/admin/communication/websites/agenda/events/show.html.erb
index 013f849125f8efd89558773c7efdf81c565f779b..41591946ed92224b27de1c888615352b50f2b1ae 100644
--- a/app/views/admin/communication/websites/agenda/events/show.html.erb
+++ b/app/views/admin/communication/websites/agenda/events/show.html.erb
@@ -8,7 +8,7 @@
         <% if @event.subtitle.present? %>
           <p class="mt-n3 text-muted"><%= @event.subtitle %></p>
         <% end %>
-        <p><%= render 'admin/communication/websites/agenda/events/dates', event: @event %></p>
+        <p><%= render 'admin/communication/websites/agenda/events/dates', event: @event, detailed: true %></p>
       <% end %>
     </div>
     <div class="offset-lg-1 col-lg-4">
diff --git a/config/locales/en.yml b/config/locales/en.yml
index 596d868698d538ffea00db0c2e36e9ed9b363271..6e2adf9f08597daeb482cfe73fda7ed6f7ad76c0 100644
--- a/config/locales/en.yml
+++ b/config/locales/en.yml
@@ -165,6 +165,7 @@ en:
   date:
     formats:
       birthday: "%B %d"
+      full: "%A %-d %B %Y"
   delete: Delete
   default_images_hint: "5 MB max, %{formats}"
   devise:
diff --git a/config/locales/fr.yml b/config/locales/fr.yml
index 73b518db256be60ac53ec9e30eee64d421a19704..9ec5a600cd89079b8e189db31e92810e784272f5 100644
--- a/config/locales/fr.yml
+++ b/config/locales/fr.yml
@@ -165,6 +165,7 @@ fr:
   date:
     formats:
       birthday: "%d %B"
+      full: "%A %-d %B %Y"
   default_images_hint: "5 Mo max, %{formats}"
   delete: Supprimer
   devise: