[LON-CAPA-cvs] cvs: loncom /interface domainprefs.pm lonannounce.pm loncommon.pm lonparmset.pm /localize lonlocal.pm

raeburn lon-capa-cvs-allow@mail.lon-capa.org
Fri, 19 Sep 2008 03:27:12 -0000


This is a MIME encoded message

--raeburn1221794832
Content-Type: text/plain

raeburn		Thu Sep 18 23:27:12 2008 EDT

  Modified files:              
    /loncom/interface	loncommon.pm lonannounce.pm domainprefs.pm 
                     	lonparmset.pm 
    /loncom/localize	lonlocal.pm 
  Log:
  Bugs: 5792 and 5798.
  - Uses DateTime, DateTime::Locale, DateTime::Locale::Catalog. 
  - Disposition of events in calendar display now consistent with current time zone.
  - Timezone in effect is displayed in Calendar header line.
  - First day of week determined from date localization in effect.
  - Extra empty row eliminated from end of calendar. 
  
  - Default date localization can be set for domain from Default auth/language/timezone section of Domain Configuration.
  - Date localization can also be set for a specific course via "Set Course environement".
  - When in course context, course-specific date localization applies (if set), otherwise default date localization of domain of course (if set).  In other contexts, date localization of domain of user (if set) applies.
  
  - Currently date localization is only used to determine starting day of the week (for building calendar display).  Future uses might consider date order/format for display of dates.
  
  - &timehash() and &maketime() routines in loncommon.pm modified to use time zones.
  - &nextday() routine in lonannounce.pm modified to correctly identify next day.
  - &getdatelocale() routine added to lonlocal.pm to retrieve date locale object.
  
  
--raeburn1221794832
Content-Type: text/plain
Content-Disposition: attachment; filename="raeburn-20080918232712.txt"

Index: loncom/interface/loncommon.pm
diff -u loncom/interface/loncommon.pm:1.686 loncom/interface/loncommon.pm:1.687
--- loncom/interface/loncommon.pm:1.686	Fri Sep 12 22:37:26 2008
+++ loncom/interface/loncommon.pm	Thu Sep 18 23:27:04 2008
@@ -1,7 +1,7 @@
 # The LearningOnline Network with CAPA
 # a pile of common routines
 #
-# $Id: loncommon.pm,v 1.686 2008/09/13 02:37:26 raeburn Exp $
+# $Id: loncommon.pm,v 1.687 2008/09/19 03:27:04 raeburn Exp $
 #
 # Copyright Michigan State University Board of Trustees
 #
@@ -69,6 +69,7 @@
 use Apache::lonclonecourse();
 use LONCAPA qw(:DEFAULT :match);
 use DateTime::TimeZone;
+use DateTime::Locale::Catalog;
 
 # ---------------------------------------------- Designs
 use vars qw(%defaultdesign);
@@ -658,6 +659,57 @@
    return $output;
 }
 
+sub select_datelocale {
+    my ($name,$selected,$onchange,$includeempty)=@_;
+    my $output='<select name="'.$name.'" '.$onchange.'>'."\n";
+    if ($includeempty) {
+        $output .= '<option value=""';
+        if ($selected eq '') {
+            $output .= ' selected="selected" ';
+        }
+        $output .= '> </option>';
+    }
+    my (@possibles,%locale_names);
+    my @locales = DateTime::Locale::Catalog::Locales;
+    foreach my $locale (@locales) {
+        if (ref($locale) eq 'HASH') {
+            my $id = $locale->{'id'};
+            if ($id ne '') {
+                my $en_terr = $locale->{'en_territory'};
+                my $native_terr = $locale->{'native_territory'};
+                my @languages = &preferred_languages();
+                if (grep(/^en$/,@languages) || !@languages) {
+                    if ($en_terr ne '') {
+                        $locale_names{$id} = '('.$en_terr.')';
+                    } elsif ($native_terr ne '') {
+                        $locale_names{$id} = $native_terr;
+                    }
+                } else {
+                    if ($native_terr ne '') {
+                        $locale_names{$id} = $native_terr.' ';
+                    } elsif ($en_terr ne '') {
+                        $locale_names{$id} = '('.$en_terr.')';
+                    }
+                }
+                push (@possibles,$id);
+            }
+        }
+    }
+    foreach my $item (sort(@possibles)) {
+        $output.= '<option value="'.$item.'"';
+        if ($item eq $selected) {
+            $output.=' selected="selected"';
+        }
+        $output.=">$item";
+        if ($locale_names{$item} ne '') {
+            $output.="  $locale_names{$item}</option>\n";
+        }
+        $output.="</option>\n";
+    }
+    $output.="</select>";
+    return $output;
+}
+
 =pod
 
 =item * &linked_select_forms(...)
@@ -3354,16 +3406,21 @@
 
 
 sub timehash {
-    my @ltime=localtime(shift);
-    return ( 'seconds' => $ltime[0],
-             'minutes' => $ltime[1],
-             'hours'   => $ltime[2],
-             'day'     => $ltime[3],
-             'month'   => $ltime[4]+1,
-             'year'    => $ltime[5]+1900,
-             'weekday' => $ltime[6],
-             'dayyear' => $ltime[7]+1,
-             'dlsav'   => $ltime[8] );
+    my ($thistime) = @_;
+    my $timezone = &Apache::lonlocal::gettimezone();
+    my $dt = DateTime->from_epoch(epoch => $thistime)
+                     ->set_time_zone($timezone);
+    my $wday = $dt->day_of_week();
+    if ($wday == 7) { $wday = 0; }
+    return ( 'second' => $dt->second(),
+             'minute' => $dt->minute(),
+             'hour'   => $dt->hour(),
+             'day'     => $dt->day_of_month(),
+             'month'   => $dt->month(),
+             'year'    => $dt->year(),
+             'weekday' => $wday,
+             'dayyear' => $dt->day_of_year(),
+             'dlsav'   => $dt->is_dst() );
 }
 
 sub utc_string {
@@ -3373,6 +3430,24 @@
 
 sub maketime {
     my %th=@_;
+    my ($epoch_time,$timezone,$dt);
+    $timezone = &Apache::lonlocal::gettimezone();
+    eval {
+        $dt = DateTime->new( year   => $th{'year'},
+                             month  => $th{'month'},
+                             day    => $th{'day'},
+                             hour   => $th{'hour'},
+                             minute => $th{'minute'},
+                             second => $th{'second'},
+                             time_zone => $timezone,
+                         );
+    };
+    if (!$@) {
+        $epoch_time = $dt->epoch;
+        if ($epoch_time) {
+            return $epoch_time;
+        }
+    }
     return POSIX::mktime(
         ($th{'seconds'},$th{'minutes'},$th{'hours'},
          $th{'day'},$th{'month'}-1,$th{'year'}-1900,0,0,-1));
Index: loncom/interface/lonannounce.pm
diff -u loncom/interface/lonannounce.pm:1.70 loncom/interface/lonannounce.pm:1.71
--- loncom/interface/lonannounce.pm:1.70	Sun May 18 15:45:46 2008
+++ loncom/interface/lonannounce.pm	Thu Sep 18 23:27:04 2008
@@ -1,7 +1,7 @@
 # The LearningOnline Network
 # Announce
 #
-# $Id: lonannounce.pm,v 1.70 2008/05/18 19:45:46 www Exp $
+# $Id: lonannounce.pm,v 1.71 2008/09/19 03:27:04 raeburn Exp $
 #
 # Copyright Michigan State University Board of Trustees
 #
@@ -38,6 +38,8 @@
 use Apache::lonnet;
 use HTML::Entities();
 use LONCAPA qw(:match);
+use DateTime;
+use DateTime::TimeZone;
 
 my %todayhash;
 my %showedcheck;
@@ -292,11 +294,59 @@
 }
 
 sub nextday {
-    my %th=@_;
-    $th{'day'}++;
+    my ($tk,%th)=@_;
+    my ($incmonth,$incyear);
+    if ($th{'day'} > 27) {
+        if ($th{'month'} == 2) {
+            if ($th{'day'} == 29) { 
+                $incmonth = 1;
+            } elsif ($th{'day'} == 28) {
+                if (!&is_leap_year($tk)) {
+                   $incmonth = 1;
+                }
+            }
+        } elsif (($th{'month'} == 4) || ($th{'month'} == 6) || 
+                 ($th{'month'} == 9) || ($th{'month'} == 11)) {
+            if ($th{'day'} == 30) {
+                $incmonth = 1;
+            }
+        } elsif ($th{'day'} == 31) {
+            if ($th{'month'} == 12) {
+                $incyear = 1;
+            } else {
+                $incmonth = 1;
+            }
+        }
+        if ($incyear) {
+            $th{'day'} = 1;
+            $th{'month'} = 1;
+            $th{'year'}++;
+        } elsif ($incmonth) {
+            $th{'day'} = 1;
+            $th{'month'}++;
+        } else {
+            $th{'day'}++;
+        }
+    } else {
+        $th{'day'}++;
+    }
     return (&Apache::loncommon::maketime(%th),$th{'month'});
 }
 
+sub is_leap_year {
+    my ($thistime) = @_;
+    my ($is_leap,$timezone,$dt);
+    $timezone = &Apache::lonlocal::gettimezone();
+    eval {
+        $dt = DateTime->from_epoch(epoch => $thistime)
+                      ->set_time_zone($timezone);
+    };
+    if (!$@) {
+        $is_leap = $dt->is_leap_year;
+    }
+    return $is_leap;
+}
+
 sub display_msg {
     my ($msg) = @_;
 
@@ -323,7 +373,7 @@
 sub showday {
     my ($tk,$mode,%allcal)=@_;
     my %th=&Apache::loncommon::timehash($tk);
-    my ($nextday,$nextmonth)=&nextday(%th);
+    my ($nextday,$nextmonth)=&nextday($tk,%th);
     my @outp;
     if ($mode) {
 	my $oneday=24*3600;
@@ -415,6 +465,13 @@
     $r->print("END:VCALENDAR$crlf");
 }
 
+sub show_timezone {
+    my $tzone = &Apache::lonlocal::gettimezone();
+    my $dt = DateTime->now();
+    my $tz = DateTime::TimeZone->new( name => $tzone );
+    return &mt('([_1] time zone)',$tz->short_name_for_datetime($dt));
+}
+
 sub handler {
     my $r = shift;
     if ($r->uri=~/\.(ics|ical)$/) {
@@ -446,12 +503,15 @@
 	'&element='.$env{'form.element'};
 # --------------------------------------------- Find out first day of the month
 
-    my %firstday=&Apache::loncommon::timehash(
-       &Apache::loncommon::maketime( 'day' => 1, 'month'=> $month,
-                                     'year' => $year, 'hours' => 0,
-				     'minutes' => 0, 'seconds' => 0,
-                                     'dlsav' => -1 ));
+    my $tk = &Apache::loncommon::maketime( 'day' => 1,
+                                           'month'=> $month,
+                                           'year' => $year, 
+                                           'hour' => 0,
+				           'minute' => 0, 
+                                           'second' => 0);
+    my %firstday = &Apache::loncommon::timehash($tk);
     my $weekday=$firstday{'weekday'};
+
 # ------------------------------------------------------------ Print the screen
     my $js = <<ENDDOCUMENT;
 <script type="text/javascript">
@@ -585,7 +645,7 @@
 		      &mt('June'),&mt('July'),&mt('August'),
                       &mt('September'),&mt('October'),
                       &mt('November'),&mt('December'))[$month].' '.
-	              $year.'</h1>');
+	              $year.' '.&show_timezone().'</h1>');
 # Reached the end of times, give up
     if (($year<1970) || ($year>2037)) {
 	$r->print('<h3>No calendar available for this date.</h3>'.
@@ -599,6 +659,35 @@
     if ($env{'form.pickdate'} eq 'yes') {
 	$class .= " LC_calendar_pickdate";
     }
+# ------------------------------------------------ Determine first day of a week
+    my $datelocale =  &Apache::lonlocal::getdatelocale();
+    my $days_in_week = 7;
+    my $startweek = 0;
+    if (ref($datelocale)) {
+        $startweek = $datelocale->first_day_of_week();
+        if ($startweek == $days_in_week)  { $startweek = 0; }
+    }
+    my @days = ('Sun','Mon','Tue','Wed','Thu','Fri','Sat');
+    my @localdays;
+    if ($startweek == 0) {
+        @localdays = @days;
+    } else {
+        my $endday = $days_in_week - $startweek;
+        for (my $i=0; $i<$days_in_week; $i++) {
+            if ($i < $endday) {
+                $localdays[$i] = $days[$i+$startweek];
+            } else {
+                $localdays[$i] = $days[$i-$endday];
+            }
+        }
+    }
+
+# ----------------------------------------------------------- Weekday in locale
+    my $loc_weekday = $weekday - $startweek;
+    if ($loc_weekday < 0) {
+        $loc_weekday += $days_in_week; 
+    }
+
     $r->print(
  '<a href="/adm/announcements?month='.$pm.'&year='.$py.
  ($pickdatemode?$pickinfo:'').'">'.&mt('Previous Month').'</a> '.
@@ -607,14 +696,11 @@
  '&nbsp;&nbsp;&nbsp;<a href="/adm/announcements?month='.$todayhash{'month'}.
  '&year='.$todayhash{'year'}.
  ($pickdatemode?$pickinfo:'').'">'.&mt('Current Month').'</a><p>'.
-        '<table class="'.$class.'" cols="7" rows="5"><tr>
-<th>'.&mt('Sun').'</th>
-<th>'.&mt('Mon').'</th>
-<th>'.&mt('Tue').'</th>
-<th>'.&mt('Wed').'</th>
-<th>'.&mt('Thu').'</th>
-<th>'.&mt('Fri').'</th>
-<th>'.&mt('Sat').'</th></tr>');
+        '<table class="'.$class.'" cols="7" rows="5"><tr>');
+    for (my $i=0; $i<@localdays; $i++) {
+        $r->print('<th>'.&mt($localdays[$i]).'</th>');
+    }
+    $r->print('</tr>');
 
     my $tk=&Apache::loncommon::maketime(%firstday);
     my $outp;
@@ -622,21 +708,33 @@
 
 # ---------------------------------------------------------------- Actual table
     $r->print('<tr>');
-    for (my $i=0;$i<$weekday;$i++) { $r->print(&emptycell); }
-    for (my $i=$weekday;$i<=6;$i++) { 
+    for (my $i=0;$i<$loc_weekday;$i++) { $r->print(&emptycell); }
+    for (my $i=$loc_weekday;$i<=6;$i++) {
         ($tk,$nm,$outp)=&showday($tk,0,%allcal);
         $r->print($outp);
     }
     $r->print('</tr>');
 
+    my $lastrow = 0;
+    my $lastday = 0;
     for (my $k=0;$k<=4;$k++) {
-        $r->print('<tr>');
-        for (my $i=0;$i<=6;$i++) {
-            ($tk,$nm,$outp)=&showday($tk,0,%allcal);
-            if ($month!=$nm) { $outp=&emptycell; }
-            $r->print($outp);
+        if (!$lastrow) {
+            $r->print('<tr>');
+            for (my $i=0;$i<=6;$i++) {
+                if ($lastday) {
+                    $outp = &emptycell();
+                } else {
+                    my $currtk = $tk;
+                    ($tk,$nm,$outp)=&showday($tk,0,%allcal);
+                    if ($month!=$nm) { $lastday = 1; }
+                }
+                $r->print($outp);
+            }
+            if ($lastday) {
+                $lastrow = 1;
+            }
+            $r->print('</tr>');
         }
-        $r->print('</tr>');
     }
 # ------------------------------------------------------------------- End table
     $r->print('</table>');
Index: loncom/interface/domainprefs.pm
diff -u loncom/interface/domainprefs.pm:1.67 loncom/interface/domainprefs.pm:1.68
--- loncom/interface/domainprefs.pm:1.67	Tue Jul 22 22:50:57 2008
+++ loncom/interface/domainprefs.pm	Thu Sep 18 23:27:04 2008
@@ -1,7 +1,7 @@
 # The LearningOnline Network with CAPA
 # Handler to set domain-wide configuration settings
 #
-# $Id: domainprefs.pm,v 1.67 2008/07/23 02:50:57 raeburn Exp $
+# $Id: domainprefs.pm,v 1.68 2008/09/19 03:27:04 raeburn Exp $
 #
 # Copyright Michigan State University Board of Trustees
 #
@@ -42,6 +42,7 @@
 use File::Copy;
 use Locale::Language;
 use DateTime::TimeZone;
+use DateTime::Locale;
 
 sub handler {
     my $r=shift;
@@ -1823,7 +1824,8 @@
 
 sub print_defaults {
     my ($dom,$rowtotal) = @_;
-    my @items = ('auth_def','auth_arg_def','lang_def','timezone_def');
+    my @items = ('auth_def','auth_arg_def','lang_def','timezone_def',
+                 'datelocale_def');
     my %domdefaults = &Apache::lonnet::get_domain_defaults($dom);
     my $titles = &defaults_titles();
     my $rownum = 0;
@@ -1858,6 +1860,9 @@
         } elsif ($item eq 'timezone_def') {
             my $includeempty = 1;
             $datatable .= &Apache::loncommon::select_timezone($item,$domdefaults{$item},undef,$includeempty);
+        } elsif ($item eq 'datelocale_def') {
+            my $includeempty = 1;
+            $datatable .= &Apache::loncommon::select_datelocale($item,$domdefaults{$item},undef,$includeempty);
         } else {
             $datatable .= '<input type="text" name="'.$item.'" value="'.
                           $domdefaults{$item}.'" />';
@@ -1875,6 +1880,7 @@
                    'auth_arg_def'  => 'Default authentication argument',
                    'lang_def'      => 'Default language',
                    'timezone_def'  => 'Default timezone',
+                   'datelocale_def' => 'Default locale for dates',
                  );
     return (\%titles);
 }
@@ -4251,7 +4257,7 @@
     my ($dom,$r) = @_;
     my ($resulttext,$mailmsgtxt,%newvalues,%changes,@errors);
     my %domdefaults = &Apache::lonnet::get_domain_defaults($dom);
-    my @items = ('auth_def','auth_arg_def','lang_def','timezone_def');
+    my @items = ('auth_def','auth_arg_def','lang_def','timezone_def','datelocale_def');
     my @authtypes = ('internal','krb4','krb5','localauth');
     foreach my $item (@items) {
         $newvalues{$item} = $env{'form.'.$item};
@@ -4278,6 +4284,13 @@
                     push(@errors,$item);   
                 }
             }
+        } elsif ($item eq 'datelocale_def') {
+            if ($newvalues{$item} ne '') {
+                my @datelocale_ids = DateTime::Locale->ids();
+                if (!grep(/^\Q$newvalues{$item}\E$/,@datelocale_ids)) {
+                    push(@errors,$item);
+                }
+            }
         }
         if (grep(/^\Q$item\E$/,@errors)) {
             $newvalues{$item} = $domdefaults{$item};
@@ -4290,6 +4303,7 @@
                                        auth_arg_def => $newvalues{'auth_arg_def'},
                                        lang_def => $newvalues{'lang_def'},
                                        timezone_def => $newvalues{'timezone_def'},
+                                       datelocale_def => $newvalues{'datelocale_def'},
                                      }
                        );
     my $title = &defaults_titles();
@@ -4322,7 +4336,7 @@
             my $cachetime = 24*60*60;
             &Apache::lonnet::do_cache_new('domdefaults',$dom,
                                           $defaults_hash{'defaults'},$cachetime);
-            if ($changes{'auth_def'} || $changes{'auth_arg_def'} || $changes{'lang_def'}) {
+            if ($changes{'auth_def'} || $changes{'auth_arg_def'} || $changes{'lang_def'} || $changes{'datelocale_def'}) {
                 my $sysmail = $r->dir_config('lonSysEMail');
                 &Apache::lonmsg::sendemail($sysmail,"LON-CAPA Domain Settings Change - $dom",$mailmsgtext);
             }
Index: loncom/interface/lonparmset.pm
diff -u loncom/interface/lonparmset.pm:1.408 loncom/interface/lonparmset.pm:1.409
--- loncom/interface/lonparmset.pm:1.408	Thu Aug 28 00:42:27 2008
+++ loncom/interface/lonparmset.pm	Thu Sep 18 23:27:04 2008
@@ -1,7 +1,7 @@
 # The LearningOnline Network with CAPA
 # Handler to set parameters for assessments
 #
-# $Id: lonparmset.pm,v 1.408 2008/08/28 04:42:27 raeburn Exp $
+# $Id: lonparmset.pm,v 1.409 2008/09/19 03:27:04 raeburn Exp $
 #
 # Copyright Michigan State University Board of Trustees
 #
@@ -2357,6 +2357,8 @@
              'categories'
                  => '<b>'.&mt('Categorize course').'</b> <a href="javascript:catsbrowser()">'.
                     &mt('Display Categories').'</a>',
+             'datelocale' 
+                 => '<b>'.&mt('Locale used for course calendar').'</b>',
              );
         my @Display_Order = ('url','description','courseid','cloners');
         (my $can_toggle_cat,$can_categorize) = &can_modify_catsettings($dom);
@@ -2380,6 +2382,7 @@
                              'allow_discussion_post_editing',
                              'languages',
                              'timezone',
+                             'datelocale',
 			     'nothideprivileged',
                              'rndseed',
                              'receiptalg',
@@ -2433,6 +2436,17 @@
                     &Apache::loncommon::select_timezone($parameter.'_value',
                                                         $timezone,
                                                         $onchange,$includeempty).'</td>';
+            } elsif ($parameter eq 'datelocale') {
+                my $includeempty = 1;
+                my $locale_obj = &Apache::lonlocal::getdatelocale();
+                my $currdatelocale;
+                if (ref($locale_obj)) {
+                    $currdatelocale = $locale_obj->id();
+                }
+                $output .= '<td>'.
+                    &Apache::loncommon::select_datelocale($parameter.'_value',
+                                                          $currdatelocale,
+                                                          $onchange,$includeempty).'</td>'; 
             } elsif ($parameter eq 'categories') {
                 my $catdisplay;
                 if ($values{'categories'} ne '') {
Index: loncom/localize/lonlocal.pm
diff -u loncom/localize/lonlocal.pm:1.48 loncom/localize/lonlocal.pm:1.49
--- loncom/localize/lonlocal.pm:1.48	Fri Sep 12 22:37:29 2008
+++ loncom/localize/lonlocal.pm	Thu Sep 18 23:27:04 2008
@@ -1,7 +1,7 @@
 # The LearningOnline Network with CAPA
 # Localization routines
 #
-# $Id: lonlocal.pm,v 1.48 2008/09/13 02:37:29 raeburn Exp $
+# $Id: lonlocal.pm,v 1.49 2008/09/19 03:27:04 raeburn Exp $
 #
 # Copyright Michigan State University Board of Trustees
 #
@@ -166,6 +166,7 @@
 use POSIX qw(locale_h strftime);
 use DateTime();
 use DateTime::TimeZone;
+use DateTime::Locale;
 
 require Exporter;
 
@@ -366,6 +367,38 @@
     }
 }
 
+sub getdatelocale {
+    my ($datelocale,$locale_obj);
+    if ($Apache::lonnet::env{'course.'.$Apache::lonnet::env{'request.course.id'}.'.datelocale'}) {
+        $datelocale = $Apache::lonnet::env{'course.'.$Apache::lonnet::env{'request.course.id'}.'.datelocale'};
+    } elsif ($Apache::lonnet::env{'request.course.id'} ne '') {
+        my $cdom = $Apache::lonnet::env{'course.'.$Apache::lonnet::env{'request.course.id'}.'.domain'};
+        if ($cdom ne '') {
+            my %domdefaults = &Apache::lonnet::get_domain_defaults($cdom);
+            if ($domdefaults{'datelocale_def'} ne '') {
+                $datelocale = $domdefaults{'datelocale_def'};
+            }
+        }
+    } elsif ($Apache::lonnet::env{'user.domain'} ne '') {
+        my %udomdefaults = &Apache::lonnet::get_domain_defaults($Apache::lonnet::env{'user.domain'});
+        if ($udomdefaults{'datelocale_def'} ne '') {
+            $datelocale = $udomdefaults{'datelocale_def'};
+        }
+    }
+    if ($datelocale ne '') {
+        eval {
+            $locale_obj = DateTime::Locale->load($datelocale);
+        };
+        if (!$@) {
+            if ($locale_obj->id() eq $datelocale) {
+                return $locale_obj;
+            }
+        }
+    }
+    return $locale_obj;
+}
+
+
 # ==================== Normalize string (reduce fragility in the lexicon files)
 
 # This normalizes a string to reduce fragility in the lexicon files of

--raeburn1221794832--