embedded/mx/DateTime/ARPA.py
changeset 0 b97547f5f1fa
equal deleted inserted replaced
-1:000000000000 0:b97547f5f1fa
       
     1 """ This module provides a set of constructors and routines to convert
       
     2     between DateTime[Delta] instances and ARPA representations of date
       
     3     and time. The format is specified by RFC822 + RFC1123.
       
     4 
       
     5     Note: Timezones are only interpreted by ParseDateTimeGMT(). All
       
     6     other constructors silently ignore the time zone information.
       
     7 
       
     8     Copyright (c) 1998-2000, Marc-Andre Lemburg; mailto:mal@lemburg.com
       
     9     Copyright (c) 2000-2007, eGenix.com Software GmbH; mailto:info@egenix.com
       
    10     See the documentation for further information on copyrights,
       
    11     or contact the author. All Rights Reserved.
       
    12 
       
    13 """
       
    14 import DateTime,Timezone
       
    15 import re,string
       
    16 
       
    17 # Grammar: RFC822 + RFC1123 + depreciated RFC850
       
    18 _litday = '(?P<litday>Mon|Tue|Wed|Thu|Fri|Sat|Sun)[a-z]*'
       
    19 _litmonth = '(?P<litmonth>Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec)'\
       
    20             '[a-z]*'
       
    21 _date = ('(?:(?P<day>\d?\d)(?: +' + _litmonth + 
       
    22          ' +|-(?P<month>\d?\d)-)(?P<year>(?:\d\d)?\d\d))')
       
    23 _zone = Timezone.zone
       
    24 _time = ('(?:(?P<hour>\d\d):(?P<minute>\d\d)'
       
    25          '(?::(?P<second>\d\d))?(?: +'+_zone+')?)')
       
    26 #       Timezone information is made optional because some mail apps
       
    27 #       forget to add it (most of these seem to be spamming engines, btw).
       
    28 #       It defaults to UTC.
       
    29 
       
    30 _arpadate = '(?:'+ _litday + ',? )? *' + _date
       
    31 _arpadatetime = '(?:'+ _litday + ',? )? *' + _date + ' +' + _time
       
    32 
       
    33 #       We are not strict about the extra characters: some applications
       
    34 #       add extra information to the date header field. Additional spaces
       
    35 #       between the fields and extra characters in the literal day
       
    36 #       and month fields are also silently ignored.
       
    37 
       
    38 arpadateRE = re.compile(_arpadate)
       
    39 arpadatetimeRE = re.compile(_arpadatetime)
       
    40 
       
    41 # Translation tables
       
    42 litdaytable = {'mon':0, 'tue':1, 'wed':2, 'thu':3, 'fri':4, 'sat':5, 'sun':6 }
       
    43 litmonthtable = {'jan':1, 'feb':2, 'mar':3, 'apr':4, 'may':5, 'jun':6,
       
    44                  'jul':7, 'aug':8, 'sep':9, 'oct':10, 'nov':11, 'dec':12 }
       
    45 _days = ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun']
       
    46 _months = [None, 'Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun',
       
    47                  'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec' ]
       
    48 
       
    49 def ParseDate(arpastring,parse_arpadate=arpadateRE.match,
       
    50 
       
    51               strip=string.strip,atoi=string.atoi,atof=string.atof,
       
    52               lower=string.lower):
       
    53 
       
    54     """ParseDate(arpastring)
       
    55 
       
    56        Returns a DateTime instance reflecting the given ARPA
       
    57        date. Only the date part is parsed, any time part will be
       
    58        ignored. The instance's time is set to 0:00:00.
       
    59 
       
    60     """
       
    61     s = strip(arpastring)
       
    62     date = parse_arpadate(s)
       
    63     if not date:
       
    64         raise ValueError,'wrong format'
       
    65     litday,day,litmonth,month,year = date.groups()
       
    66     if len(year) == 2:
       
    67         year = DateTime.add_century(atoi(year))
       
    68     else:
       
    69         year = atoi(year)
       
    70     if litmonth:
       
    71         litmonth = lower(litmonth)
       
    72         try:
       
    73             month = litmonthtable[litmonth]
       
    74         except KeyError:
       
    75             raise ValueError,'wrong month format'
       
    76     else:
       
    77         month = atoi(month)
       
    78     day = atoi(day)
       
    79     # litday and timezone are ignored
       
    80     return DateTime.DateTime(year,month,day)
       
    81 
       
    82 def ParseDateTime(arpastring,parse_arpadatetime=arpadatetimeRE.match,
       
    83 
       
    84                   strip=string.strip,atoi=string.atoi,atof=string.atof,
       
    85                   lower=string.lower):
       
    86 
       
    87     """ParseDateTime(arpastring)
       
    88 
       
    89        Returns a DateTime instance reflecting the given ARPA date assuming
       
    90        it is local time (timezones are silently ignored).
       
    91     """
       
    92     s = strip(arpastring)
       
    93     date = parse_arpadatetime(s)
       
    94     if not date:
       
    95         raise ValueError,'wrong format or unknown time zone'
       
    96     litday,day,litmonth,month,year,hour,minute,second,zone = date.groups()
       
    97     if len(year) == 2:
       
    98         year = DateTime.add_century(atoi(year))
       
    99     else:
       
   100         year = atoi(year)
       
   101     if litmonth:
       
   102         litmonth = lower(litmonth)
       
   103         try:
       
   104             month = litmonthtable[litmonth]
       
   105         except KeyError:
       
   106             raise ValueError,'wrong month format'
       
   107     else:
       
   108         month = atoi(month)
       
   109     day = atoi(day)
       
   110     hour = atoi(hour)
       
   111     minute = atoi(minute)
       
   112     if second is None:
       
   113         second = 0.0
       
   114     else:
       
   115         second = atof(second)
       
   116     # litday and timezone are ignored
       
   117     return DateTime.DateTime(year,month,day,hour,minute,second)
       
   118 
       
   119 def ParseDateTimeGMT(arpastring,parse_arpadatetime=arpadatetimeRE.match,
       
   120 
       
   121                      strip=string.strip,atoi=string.atoi,atof=string.atof,
       
   122                      lower=string.lower):
       
   123 
       
   124     """ParseDateTimeGMT(arpastring)
       
   125 
       
   126        Returns a DateTime instance reflecting the given ARPA date converting
       
   127        it to UTC (timezones are honored).
       
   128     """
       
   129     s = strip(arpastring)
       
   130     date = parse_arpadatetime(s)
       
   131     if not date:
       
   132         raise ValueError,'wrong format or unknown time zone'
       
   133     litday,day,litmonth,month,year,hour,minute,second,zone = date.groups()
       
   134     if len(year) == 2:
       
   135         year = DateTime.add_century(atoi(year))
       
   136     else:
       
   137         year = atoi(year)
       
   138     if litmonth:
       
   139         litmonth = lower(litmonth)
       
   140         try:
       
   141             month = litmonthtable[litmonth]
       
   142         except KeyError:
       
   143             raise ValueError,'wrong month format'
       
   144     else:
       
   145         month = atoi(month)
       
   146     day = atoi(day)
       
   147     hour = atoi(hour)
       
   148     minute = atoi(minute)
       
   149     if second is None:
       
   150         second = 0.0
       
   151     else:
       
   152         second = atof(second)
       
   153     offset = Timezone.utc_offset(zone)
       
   154     # litday is ignored
       
   155     return DateTime.DateTime(year,month,day,hour,minute,second) - offset
       
   156 
       
   157 # Alias
       
   158 ParseDateTimeUTC = ParseDateTimeGMT
       
   159 
       
   160 def str(datetime,tz=None):
       
   161 
       
   162     """str(datetime,tz=DateTime.tz_offset(datetime))
       
   163 
       
   164     Returns the datetime instance as ARPA date string. tz can be given
       
   165     as DateTimeDelta instance providing the time zone difference from
       
   166     datetime's zone to UTC. It defaults to
       
   167     DateTime.tz_offset(datetime) which assumes local time. """
       
   168 
       
   169     if tz is None:
       
   170         tz = datetime.gmtoffset()
       
   171     return '%s, %02i %s %04i %02i:%02i:%02i %+03i%02i' % (
       
   172         _days[datetime.day_of_week], datetime.day, 
       
   173         _months[datetime.month], datetime.year,
       
   174         datetime.hour, datetime.minute, datetime.second,
       
   175         tz.hour,tz.minute)
       
   176 
       
   177 def strGMT(datetime):
       
   178 
       
   179     """ strGMT(datetime)
       
   180 
       
   181     Returns the datetime instance as ARPA date string assuming it
       
   182     is given in GMT. """
       
   183 
       
   184     return '%s, %02i %s %04i %02i:%02i:%02i GMT' % (
       
   185         _days[datetime.day_of_week], datetime.day, 
       
   186         _months[datetime.month], datetime.year,
       
   187         datetime.hour, datetime.minute, datetime.second)
       
   188 
       
   189 def strUTC(datetime):
       
   190 
       
   191     """ strUTC(datetime)
       
   192 
       
   193     Returns the datetime instance as ARPA date string assuming it
       
   194     is given in UTC. """
       
   195 
       
   196     return '%s, %02i %s %04i %02i:%02i:%02i UTC' % (
       
   197         _days[datetime.day_of_week], datetime.day, 
       
   198         _months[datetime.month], datetime.year,
       
   199         datetime.hour, datetime.minute, datetime.second)
       
   200 
       
   201 def _test():
       
   202     import sys, os, rfc822
       
   203     file = os.path.join(os.environ['HOME'], 'nsmail/Inbox')
       
   204     f = open(file, 'r')
       
   205     while 1:
       
   206         m = rfc822.Message(f)
       
   207         if not m:
       
   208             break
       
   209         print 'From:', m.getaddr('from')
       
   210         print 'To:', m.getaddrlist('to')
       
   211         print 'Subject:', m.getheader('subject')
       
   212         raw = m.getheader('date')
       
   213         try:
       
   214             date = ParseDateTimeUTC(raw)
       
   215             print 'Date:',strUTC(date)
       
   216         except ValueError,why:
       
   217             print 'PROBLEMS:',repr(raw),'-->',why
       
   218             raw_input('...hit return to continue')
       
   219         print
       
   220         # Netscape mail file
       
   221         while 1:
       
   222             line = f.readline()
       
   223             if line[:6] == 'From -':
       
   224                 break
       
   225 
       
   226 if __name__ == '__main__':
       
   227     _test()