Subject: Re: correct for timezone in index format

From: Tony Tung <[email-masked]>
Date: Fri, 1 Mar 2002 16:26:31 -0800 (PST)

Hi all,

Sadly, no one responded to my question so I wrote a patch for this.  In
addition to fixing the timezone problem, it adds a mail index token
SMARTTIME6.  It shows the time the email was sent if it was sent today.
Otherwise it shows the date.

Enclosed are two patches.  One patches the pine4.44 distribution, and the
other patches pine4.44 with Eduardo Chappa's fancy thread feature.  I hope
someone finds this useful.

Thanks,
Tony

On Tue, 22 Jan 2002, Tony Tung wrote:

>
> Hi all,
>
> Is there a way to have pine correct for the timezone when displaying the
> date/time in the index?  All the date/time tokens appear to not correct
> for the timezone.  Without such a feature, there are messages that appear
> to be arriving from the future :).
>
> Thanks,
> Tony
>
>

diff -rc pine4.44/pine/mailindx.c pine4.44-s6t/pine/mailindx.c
*** pine4.44/pine/mailindx.c	Wed Nov 21 08:56:17 2001
--- pine4.44-s6t/pine/mailindx.c	Fri Mar  1 16:02:56 2002
***************
*** 1989,1994 ****
--- 1989,1995 ----
  	      case iIStatus:
  	      case iDate:
  	      case iScore:
+  	      case iSTime6:
  		(*answer)[column].req_width = 6;
  		break;
  	      case iTime12:
***************
*** 2049,2054 ****
--- 2050,2056 ----
      {"SMARTDATE",	iSDate,		FOR_INDEX|FOR_REPLY_INTRO|FOR_TEMPLATE},
      {"SMARTTIME",	iSTime,		FOR_INDEX|FOR_REPLY_INTRO|FOR_TEMPLATE},
      {"SMARTDATETIME",	iSDateTime,	FOR_INDEX|FOR_REPLY_INTRO|FOR_TEMPLATE},
+     {"SMARTTIME6",	iSTime6,	FOR_INDEX|FOR_REPLY_INTRO|FOR_TEMPLATE},
      {"TIME24",		iTime24,	FOR_INDEX|FOR_REPLY_INTRO|FOR_TEMPLATE},
      {"TIME12",		iTime12,	FOR_INDEX|FOR_REPLY_INTRO|FOR_TEMPLATE},
      {"TIMEZONE",	iTimezone,	FOR_INDEX|FOR_REPLY_INTRO|FOR_TEMPLATE},
***************
*** 2314,2319 ****
--- 2316,2323 ----
  	    cdesc->adjustment = Left;
  	    break;
  
+           case iSTime6:
+             set_format_includes_smartdate();
  	  case iFStatus:
  	  case iIStatus:
  	  case iDate:
***************
*** 2445,2451 ****
      for(j = 0; space_left > 0 && some_to_calculate; j++){
        static IndexColType targetctype[] = {
  	iMessNo, iStatus, iFStatus, iIStatus, iDate, iSDate, iSDateTime,
! 	iSTime, iLDate,
  	iS1Date, iS2Date, iS3Date, iS4Date, iDateIso, iDateIsoS,
  	iSize, iSizeComma, iSizeNarrow, iKSize, iDescripSize,
  	iAtt, iTime24, iTime12, iTimezone, iMonAbb
--- 2449,2455 ----
      for(j = 0; space_left > 0 && some_to_calculate; j++){
        static IndexColType targetctype[] = {
  	iMessNo, iStatus, iFStatus, iIStatus, iDate, iSDate, iSDateTime,
! 	iSTime, iSTime6, iLDate,
  	iS1Date, iS2Date, iS3Date, iS4Date, iDateIso, iDateIsoS,
  	iSize, iSizeComma, iSizeNarrow, iKSize, iDescripSize,
  	iAtt, iTime24, iTime12, iTimezone, iMonAbb
***************
*** 3324,3329 ****
--- 3328,3334 ----
  	      case iLDate:
  	      case iSDate:
  	      case iSTime:
+ 	      case iSTime6:
  	      case iSDateTime:
  	      case iS1Date:
  	      case iS2Date:
***************
*** 4587,4594 ****
  	rfc822_date(dbuf);
  	parse_date(dbuf, &d);
      }
!     else
        parse_date(datesrc, &d);
  
      switch(type){
        case iSDate:
--- 4592,4601 ----
  	rfc822_date(dbuf);
  	parse_date(dbuf, &d);
      }
!     else {
        parse_date(datesrc, &d);
+       adjust_for_timezone(&d);
+     }
  
      switch(type){
        case iSDate:
***************
*** 4845,4850 ****
--- 4852,4897 ----
  		  (hour12[0] && minzero[0] && d.hour >= 12) ? "pm" :
  		    "  ");
  	break;
+       case iSTime6:
+         { struct date now;
+ 	  char        dbuf[200];
+ 
+ 	  str[0] = '\0';
+ 	  rfc822_date(dbuf);
+ 	  parse_date(dbuf, &now);
+ 
+ 	  if((d.year != now.year) ||
+              (d.month != now.month) ||
+              (d.day != now.day)){
+                                 /* not today: "Mmmyy" */
+ 
+ 	      strcpy(monabb, (d.month >= 1 && d.month <= 12) ?
+                               month_abbrev(d.month) : "???");
+ 
+ 	      sprintf(str, "%s %d", monabb, d.day);
+ 	  }
+ 	  else{  /* Date is within last 7 days: */
+             hr12 = (d.hour == 0) ? 12 :
+               (d.hour > 12) ? (d.hour - 12) : d.hour;
+             hour12[0] = '\0';
+             if(hr12 > 0 && hr12 <= 12)
+               strcpy(hour12, int2string(hr12));
+ 
+             if(d.minute >= 0 && d.minute < 60)
+               sprintf(minzero, "%02d", d.minute);
+             else
+               strcpy(minzero, "??");
+ 
+             sprintf(str, "%s%c%2s%s",
+                     (hour12[0] && minzero[0]) ? hour12 : "",
+                     (hour12[0] && minzero[0]) ? ':' : ' ',
+                     (hour12[0] && minzero[0]) ? minzero : "",
+                     (hour12[0] && minzero[0] && d.hour < 12) ? "a" :
+                     (hour12[0] && minzero[0] && d.hour >= 12) ? "p" :
+ 		    "  ");
+           }
+         }      
+         break;
        case iSDate:
        case iSDateTime:
  	{ struct date now, last_day;
diff -rc pine4.44/pine/pine.h pine4.44-s6t/pine/pine.h
*** pine4.44/pine/pine.h	Tue Jan  8 12:55:49 2002
--- pine4.44-s6t/pine/pine.h	Fri Mar  1 16:00:14 2002
***************
*** 1647,1653 ****
  	      iFromTo, iFromToNotNews, iFrom, iTo, iSender, iCc, iNews, iRecips,
  	      iMailbox, iAddress, iInit, iCursorPos,
  	      iDay2Digit, iMon2Digit, iYear2Digit,
! 	      iSTime, iKSize,
  	      iScore,
  	      iDay, iDayOrdinal, iMonAbb, iMonLong, iMon, iYear} IndexColType;
  typedef enum {AllAuto, Fixed, Percent, WeCalculate, Special} WidthType;
--- 1647,1653 ----
  	      iFromTo, iFromToNotNews, iFrom, iTo, iSender, iCc, iNews, iRecips,
  	      iMailbox, iAddress, iInit, iCursorPos,
  	      iDay2Digit, iMon2Digit, iYear2Digit,
! 	      iSTime, iSTime6, iKSize,
  	      iScore,
  	      iDay, iDayOrdinal, iMonAbb, iMonLong, iMon, iYear} IndexColType;
  typedef enum {AllAuto, Fixed, Percent, WeCalculate, Special} WidthType;
***************
*** 4051,4056 ****
--- 4051,4057 ----
  char	   *week_abbrev PROTO((int));
  int	    month_num PROTO((char *));
  void	    parse_date PROTO((char *, struct date *));
+ void	    adjust_for_timezone PROTO((struct date *));
  int	    compare_dates PROTO((MESSAGECACHE *, MESSAGECACHE *));
  void	    convert_to_gmt PROTO((MESSAGECACHE *));
  char	   *pretty_command PROTO((int));
diff -rc pine4.44/pine/strings.c pine4.44-s6t/pine/strings.c
*** pine4.44/pine/strings.c	Thu Oct 18 12:19:04 2001
--- pine4.44-s6t/pine/strings.c	Fri Mar  1 16:00:14 2002
***************
*** 974,979 ****
--- 974,1142 ----
  }

+ static int 
+ max_day(m, y)
+   int m;
+   int y;
+ {
+   if ((1 == m % 2 && 
+        m <= 6) ||
+       (0 == m % 2 &&
+        m >= 7))
+   {
+     return 31;
+   }
+   else if (2 != m)
+   {
+     return 30;
+   }
+   else
+   {
+     if (0 != y % 4)
+     {
+       return 28;                                            // no leap year
+     }
+     else if (0 == y % 400)
+     {
+       return 29;                                            // every 400 yrs
+     }
+     else if (0 == y % 100)
+     {
+       return 28;                                            // skipped leap year
+     }
+     else
+     {
+       return 29;                                            // normal leap year
+     }
+   }
+ }
+ 
+ 
+ void
+ adjust_for_timezone(d)
+   struct date *d;
+ {
+   static int tz_hour_off;
+   static int tz_min_off;
+   static int tz_valid = 0;
+ 
+   int adj_hour_off;
+   int adj_min_off;
+ 
+   int doff;
+ 
+   /* get the current timezone */
+   if (0 == tz_valid)
+   {
+     /* no timezone available */
+     char dbuf[200];
+     struct date td;
+     
+     rfc822_date(dbuf);
+     parse_date(dbuf, &td);
+ 
+     /* get the offset for the current timezone */
+     tz_hour_off = td.hours_off_gmt;
+     tz_min_off = td.min_off_gmt;
+     tz_valid = 1;
+   }
+ 
+   /* merge the offsets.  if they cancel out, don't tamper with anything */
+   adj_hour_off = tz_hour_off - d->hours_off_gmt;
+   adj_min_off = tz_min_off - d->min_off_gmt;
+ 
+   if (0 == adj_hour_off &&
+       0 == adj_min_off)
+     return;
+ 
+   /* adjust the current time */
+   d->hours_off_gmt = tz_hour_off;
+   d->min_off_gmt = tz_min_off;
+ 
+   d->hour += adj_hour_off;
+   d->minute += adj_min_off;
+ 
+   /* clean up any overflow of date ranges */
+ 
+   /* minute... */
+   if (d->minute < 0)
+   {
+     d->hour --;
+     d->minute += 60;
+   }
+   else if (d->minute >= 60)
+   {
+     d->hour ++;
+     d->minute -= 60;
+   }
+ 
+   /* hour... */
+   if (d->hour < 0)
+   {
+     doff = -1;
+     d->hour += 24;
+   }
+   else if (d->hour >= 24)
+   {
+     doff = 1;
+     d->hour -= 24;
+   }
+   else
+   {
+     return;
+   }
+ 
+   /* have to adjust day! */
+   d->wkday = (d->wkday + 7 + doff) % 7;
+ 
+   if (-1 == doff)
+   {
+     /* look for beginning of month conditions */
+     if (1 == d->day)
+     {
+       /* 1st day of year? */
+       if (1 == d->month)
+       {
+         d->year --;
+         d->month = 12;
+         d->day = 31;
+         return;
+       }
+       else
+       {
+         /* find max # of days in previous month */
+         d->month --;
+         d->day = max_day(d->month - 1, d->year);
+       }
+     }
+     else
+     {
+       d->day --;
+     }
+   }
+   else if (1 == doff)
+   {
+     if (max_day(d->month, d->year) == d->day)
+     {
+       if (d->month == 12)
+       {
+         d->year ++;
+         d->month = 1;
+         d->day = 1;
+       }
+       else
+       {
+         d->month ++;
+         d->day = 1;
+       }
+     }
+     else
+     {
+       d->day ++;
+     }
+   }
+ }
+ 
  
  /*----------------------------------------------------------------------
       Map some of the special characters into sensible strings for human
diff -rc pine4.44-f/pine/mailindx.c pine4.44-fs6t/pine/mailindx.c
*** pine4.44-f/pine/mailindx.c	Fri Mar  1 16:07:06 2002
--- pine4.44-fs6t/pine/mailindx.c	Fri Mar  1 15:30:36 2002
***************
*** 2091,2096 ****
--- 2091,2097 ----
  	      case iIStatusThread:
  	      case iDate:
  	      case iScore:
+  	      case iSTime6:
  		(*answer)[column].req_width = 6;
  		break;
  	      case iTime12:
***************
*** 2169,2174 ****
--- 2170,2176 ----
      {"SMARTDATE",	iSDate,		FOR_INDEX|FOR_THREAD|FOR_REPLY_INTRO|FOR_TEMPLATE},
      {"SMARTTIME",	iSTime,		FOR_INDEX|FOR_THREAD|FOR_REPLY_INTRO|FOR_TEMPLATE},
      {"SMARTDATETIME",	iSDateTime,	FOR_INDEX|FOR_THREAD|FOR_REPLY_INTRO|FOR_TEMPLATE},
+     {"SMARTTIME6",	iSTime6,	FOR_INDEX|FOR_THREAD|FOR_REPLY_INTRO|FOR_TEMPLATE},
      {"TIME24",		iTime24,	FOR_INDEX|FOR_THREAD|FOR_REPLY_INTRO|FOR_TEMPLATE},
      {"TIME12",		iTime12,	FOR_INDEX|FOR_THREAD|FOR_REPLY_INTRO|FOR_TEMPLATE},
      {"TIMEZONE",	iTimezone,	FOR_INDEX|FOR_THREAD|FOR_REPLY_INTRO|FOR_TEMPLATE},
***************
*** 2438,2443 ****
--- 2440,2447 ----
  	    cdesc->adjustment = Left;
  	    break;
  
+           case iSTime6:
+             set_format_includes_smartdate();
  	  case iFStatus:
  	  case iIStatus:
  	  case iIStatusThread:
***************
*** 2591,2597 ****
        static IndexColType targetctype[] = {
  	iMessNo, iStatus, iFStatus, iIStatus, iStatusThread, iIStatusThread,
  	iDate, iSDate, iSDateTime,
! 	iSTime, iLDate,
  	iS1Date, iS2Date, iS3Date, iS4Date, iDateIso, iDateIsoS,
  	iSize, iSizeComma, iSizeNarrow, iKSize, iDescripSize,
  	iAtt, iTime24, iTime12, iTimezone, iMonAbb,
--- 2595,2601 ----
        static IndexColType targetctype[] = {
  	iMessNo, iStatus, iFStatus, iIStatus, iStatusThread, iIStatusThread,
  	iDate, iSDate, iSDateTime,
! 	iSTime, iSTime6, iLDate,
  	iS1Date, iS2Date, iS3Date, iS4Date, iDateIso, iDateIsoS,
  	iSize, iSizeComma, iSizeNarrow, iKSize, iDescripSize,
  	iAtt, iTime24, iTime12, iTimezone, iMonAbb,
***************
*** 3638,3643 ****
--- 3642,3648 ----
  	      case iLDate:
  	      case iSDate:
  	      case iSTime:
+ 	      case iSTime6:
  	      case iSDateTime:
  	      case iS1Date:
  	      case iS2Date:
***************
*** 5014,5021 ****
  	rfc822_date(dbuf);
  	parse_date(dbuf, &d);
      }
!     else
        parse_date(datesrc, &d);
  
      switch(type){
        case iSDate:
--- 5019,5028 ----
  	rfc822_date(dbuf);
  	parse_date(dbuf, &d);
      }
!     else {
        parse_date(datesrc, &d);
+       adjust_for_timezone(&d);
+     }
  
      switch(type){
        case iSDate:
***************
*** 5272,5277 ****
--- 5279,5324 ----
  		  (hour12[0] && minzero[0] && d.hour >= 12) ? "pm" :
  		    "  ");
  	break;
+       case iSTime6:
+         { struct date now;
+ 	  char        dbuf[200];
+ 
+ 	  str[0] = '\0';
+ 	  rfc822_date(dbuf);
+ 	  parse_date(dbuf, &now);
+ 
+ 	  if((d.year != now.year) ||
+              (d.month != now.month) ||
+              (d.day != now.day)){
+                                 /* not today: "Mmmyy" */
+ 
+ 	      strcpy(monabb, (d.month >= 1 && d.month <= 12) ?
+                               month_abbrev(d.month) : "???");
+ 
+ 	      sprintf(str, "%s %d", monabb, d.day);
+ 	  }
+ 	  else{  /* Date is within last 7 days: */
+             hr12 = (d.hour == 0) ? 12 :
+               (d.hour > 12) ? (d.hour - 12) : d.hour;
+             hour12[0] = '\0';
+             if(hr12 > 0 && hr12 <= 12)
+               strcpy(hour12, int2string(hr12));
+ 
+             if(d.minute >= 0 && d.minute < 60)
+               sprintf(minzero, "%02d", d.minute);
+             else
+               strcpy(minzero, "??");
+ 
+             sprintf(str, "%s%c%2s%s",
+                     (hour12[0] && minzero[0]) ? hour12 : "",
+                     (hour12[0] && minzero[0]) ? ':' : ' ',
+                     (hour12[0] && minzero[0]) ? minzero : "",
+                     (hour12[0] && minzero[0] && d.hour < 12) ? "a" :
+                     (hour12[0] && minzero[0] && d.hour >= 12) ? "p" :
+ 		    "  ");
+           }
+         }      
+         break;
        case iSDate:
        case iSDateTime:
  	{ struct date now, last_day;
diff -rc pine4.44-f/pine/pine.h pine4.44-fs6t/pine/pine.h
*** pine4.44-f/pine/pine.h	Fri Mar  1 16:07:04 2002
--- pine4.44-fs6t/pine/pine.h	Fri Mar  1 15:30:31 2002
***************
*** 1676,1682 ****
  	      iFromTo, iFromToNotNews, iFrom, iTo, iSender, iCc, iNews, iRecips,
  	      iMailbox, iAddress, iInit, iCursorPos,
  	      iDay2Digit, iMon2Digit, iYear2Digit,
! 	      iSTime, iKSize,
  	      iScore,
  	      iDay, iDayOrdinal, iMonAbb, iMonLong, iMon, iYear} IndexColType;
  typedef enum {AllAuto, Fixed, Percent, WeCalculate, Special} WidthType;
--- 1676,1682 ----
  	      iFromTo, iFromToNotNews, iFrom, iTo, iSender, iCc, iNews, iRecips,
  	      iMailbox, iAddress, iInit, iCursorPos,
  	      iDay2Digit, iMon2Digit, iYear2Digit,
! 	      iSTime, iSTime6, iKSize,
  	      iScore,
  	      iDay, iDayOrdinal, iMonAbb, iMonLong, iMon, iYear} IndexColType;
  typedef enum {AllAuto, Fixed, Percent, WeCalculate, Special} WidthType;
***************
*** 4109,4114 ****
--- 4109,4115 ----
  char	   *week_abbrev PROTO((int));
  int	    month_num PROTO((char *));
  void	    parse_date PROTO((char *, struct date *));
+ void	    adjust_for_timezone PROTO((struct date *));
  int	    compare_dates PROTO((MESSAGECACHE *, MESSAGECACHE *));
  void	    convert_to_gmt PROTO((MESSAGECACHE *));
  char	   *pretty_command PROTO((int));
diff -rc pine4.44-f/pine/strings.c pine4.44-fs6t/pine/strings.c
*** pine4.44-f/pine/strings.c	Fri Mar  1 16:07:05 2002
--- pine4.44-fs6t/pine/strings.c	Fri Mar  1 15:30:33 2002
***************
*** 974,979 ****
--- 974,1142 ----
  }

+ static int 
+ max_day(m, y)
+   int m;
+   int y;
+ {
+   if ((1 == m % 2 && 
+        m <= 6) ||
+       (0 == m % 2 &&
+        m >= 7))
+   {
+     return 31;
+   }
+   else if (2 != m)
+   {
+     return 30;
+   }
+   else
+   {
+     if (0 != y % 4)
+     {
+       return 28;                                            // no leap year
+     }
+     else if (0 == y % 400)
+     {
+       return 29;                                            // every 400 yrs
+     }
+     else if (0 == y % 100)
+     {
+       return 28;                                            // skipped leap year
+     }
+     else
+     {
+       return 29;                                            // normal leap year
+     }
+   }
+ }
+ 
+ 
+ void
+ adjust_for_timezone(d)
+   struct date *d;
+ {
+   static int tz_hour_off;
+   static int tz_min_off;
+   static int tz_valid = 0;
+ 
+   int adj_hour_off;
+   int adj_min_off;
+ 
+   int doff;
+ 
+   /* get the current timezone */
+   if (0 == tz_valid)
+   {
+     /* no timezone available */
+     char dbuf[200];
+     struct date td;
+     
+     rfc822_date(dbuf);
+     parse_date(dbuf, &td);
+ 
+     /* get the offset for the current timezone */
+     tz_hour_off = td.hours_off_gmt;
+     tz_min_off = td.min_off_gmt;
+     tz_valid = 1;
+   }
+ 
+   /* merge the offsets.  if they cancel out, don't tamper with anything */
+   adj_hour_off = tz_hour_off - d->hours_off_gmt;
+   adj_min_off = tz_min_off - d->min_off_gmt;
+ 
+   if (0 == adj_hour_off &&
+       0 == adj_min_off)
+     return;
+ 
+   /* adjust the current time */
+   d->hours_off_gmt = tz_hour_off;
+   d->min_off_gmt = tz_min_off;
+ 
+   d->hour += adj_hour_off;
+   d->minute += adj_min_off;
+ 
+   /* clean up any overflow of date ranges */
+ 
+   /* minute... */
+   if (d->minute < 0)
+   {
+     d->hour --;
+     d->minute += 60;
+   }
+   else if (d->minute >= 60)
+   {
+     d->hour ++;
+     d->minute -= 60;
+   }
+ 
+   /* hour... */
+   if (d->hour < 0)
+   {
+     doff = -1;
+     d->hour += 24;
+   }
+   else if (d->hour >= 24)
+   {
+     doff = 1;
+     d->hour -= 24;
+   }
+   else
+   {
+     return;
+   }
+ 
+   /* have to adjust day! */
+   d->wkday = (d->wkday + 7 + doff) % 7;
+ 
+   if (-1 == doff)
+   {
+     /* look for beginning of month conditions */
+     if (1 == d->day)
+     {
+       /* 1st day of year? */
+       if (1 == d->month)
+       {
+         d->year --;
+         d->month = 12;
+         d->day = 31;
+         return;
+       }
+       else
+       {
+         /* find max # of days in previous month */
+         d->month --;
+         d->day = max_day(d->month - 1, d->year);
+       }
+     }
+     else
+     {
+       d->day --;
+     }
+   }
+   else if (1 == doff)
+   {
+     if (max_day(d->month, d->year) == d->day)
+     {
+       if (d->month == 12)
+       {
+         d->year ++;
+         d->month = 1;
+         d->day = 1;
+       }
+       else
+       {
+         d->month ++;
+         d->day = 1;
+       }
+     }
+     else
+     {
+       d->day ++;
+     }
+   }
+ }
+ 
  
  /*----------------------------------------------------------------------
       Map some of the special characters into sensible strings for human