diff --git a/lib/modules/Calendar.pmod/module.pmod b/lib/modules/Calendar.pmod/module.pmod
index 2b2fada6921170c215bc2ec424e8b4599c0e0a8b..b87f1b3041a487a09c6b87e57e108a8d5aace6a2 100644
--- a/lib/modules/Calendar.pmod/module.pmod
+++ b/lib/modules/Calendar.pmod/module.pmod
@@ -114,3 +114,121 @@ class _TimeUnit
    object next() { return this+1; }
    object prev() { return this+(-1); }
 }
+
+
+
+
+//!
+//! function datetime(int|void unix_time)
+//!          Replacement for localtime.
+//!
+//! function datetime_name(int|void unix_time)
+//!          Replacement for ctime.
+//!
+//! function datetime_short_name(int|void unix_time)
+//!          Replacement for ctime.
+//!
+
+//
+// Maybe these auxiliary routines should be somewhere else? Maybe even
+// written in C?
+//
+//
+static private int ymd2jd(int y, int m, int d)
+{
+  if(m<3) {
+    y--;
+    m+=12;
+  }
+  return 1720995+d+2- (y/100) + (y/400) + (36525*y)/100 + (306001*(m+1))/10000;
+}
+
+static private int y2jd(int y)
+{
+  y--;
+  return 1721426 - (y/100) + (y/400) + (36525*y)/100;
+}
+
+static private int leapyear(int year)
+{
+  if((year%400) == 0)
+    return 1;
+  if((year%100) == 0)
+    return 0;
+  if((year%4) == 0)
+    return 1;
+  return 0;
+}
+
+static private int week(int year, int month, int day)
+{
+  int delta_day, first_time, yday, first_day, first_next_day;
+
+  first_time = y2jd(year);
+  yday = ymd2jd(year, month, day)-first_time;
+  first_day = first_time%7;
+  first_next_day = y2jd(year+1)%7;
+
+  if((yday > (364+leapyear(year)-first_next_day)) &&
+     (first_next_day <= 3))
+    return 1;
+  
+  if(first_day <= 3) {
+    /* Week begins on Thursday or erlier, means week one here. */
+    delta_day = first_day;
+  } else {
+    /* Week begins on Friday or later, means same week as last year. */
+    if(yday + first_day <= 6) {
+      /* Return the last week previous year. */
+      return week(year-1, 12, 28);
+    }
+    delta_day = first_day-7;
+  }
+  
+  /* Calculate week. Begin with week 1. */
+  return (yday + delta_day)/7 + 1;
+}
+
+// Sane replacement for localtime().
+mapping(string:int) datetime(int|void unix_time)
+{
+   mapping t = localtime(unix_time || time());
+   return ([ "year":t->year+1900,
+	     "month":t->mon+1,
+	     "day":t->mday,
+	     "hour":t->hour,
+	     "minute":t->min,
+	     "second":t->sec,
+	     "week":week(t->year+1900, t->mon+1, t->mday),
+	     // ISO weekdays begin with Monday as 1 --- Sunday as 7.
+	     "weekday":((t->wday+6)%7)+1,
+	     "yearday":t->yday,
+	     "timezone":t->timezone,
+	     // Dayligt-saving time.
+	     "DST":t->isdst ]);
+}
+
+// Sane replacement for ctime().
+string datetime_name(int|void unix_time)
+{
+  array(string) day_names = ({ "Mon", "Tue", "Wed", "Thu",
+			       "Fri", "Sat", "Sun" });
+  array(string) month_names = ({ "Jan", "Feb", "Mar", "Apr",
+				 "May", "Jun", "Jul", "Aug",
+				 "Sep", "Oct", "Nov", "Dec" });
+  
+  mapping t = datetime(unix_time);
+  return sprintf("%04d-%02d-%02d (%s) -W%02d-%d (%s) %02d:%02d:%02d",
+		 t->year, t->month, t->day, month_names[t->month-1],
+		 t->week, t->weekday, day_names[t->weekday-1],
+		 t->hour, t->minute, t->second);
+}
+
+// Sane replacement for ctime().
+string datetime_short_name(int|void unix_time)
+{
+  mapping t = datetime(unix_time);
+  return sprintf("%04d-%02d-%02d %02d:%02d:%02d",
+		 t->year, t->month, t->day,
+		 t->hour, t->minute, t->second);
+}