吵吵   2013-03-24  阅读:2,269

随着Google Reader的终结,最近考虑做一个程序用于读取独立博客的最新文章和内容,以方便自己能够及时的获得所需要的信息。实现这样一个程序并不困难,使用xml文档读取rss的路径就ok了。但是我在将rss的时间格式,转化为标准的东八区的时候遇到了困难,delphi或者很多其他的程序语言并不存在类似的库类支持这样子的转换,万般无奈就只好自己搞了。

rss时间规范

rss的时间规范是遵从RFC822规范的,RFC822是标准的邮件协议。1977年,Arpnet在他们开发的几个非正式文本消息传送标准的基础上,制订了“Arpnet网络之间文本消息格式标准”,即RFC#733。后来为了适应更大、更复杂的Arpnet网,对RFC#733作了一些修订,形成了RFC#822。虽然RFC#822是专门为Arpnet网设计的,但其他网络之间的文本消息传输也可以用。

其中规定的时间格式为:Date: Thu, 18 Jan 2001 14:21:34 +0800 (CST)

具体的规范如下:
date-time = [ day “,” ] date time ; dd mm yy; hh:mm:ss zzz

day = “Mon” / “Tue” / “Wed” / “Thu”/ “Fri” / “Sat” / “Sun”

date = 1*2DIGIT month 2DIGIT ; day month year; e.g. 20 Jun 82

month = “Jan” / “Feb” / “Mar” / “Apr”/ “May” / “Jun” / “Jul” / “Aug”/ “Sep” / “Oct” / “Nov” / “Dec”

time = hour zone ; ANSI and Military

hour = 2DIGIT “:” 2DIGIT [“:” 2DIGIT]; 00:00:00 – 23:59:59

zone = “UT” / “GMT” ; Universal Time;

North American : UT/ “EST” / “EDT” ;
Eastern: – 5/ – 4/ “CST” / “CDT” ;
Central: – 6/ – 5/ “MST” / “MDT” ;
Mountain: – 7/ – 6/ “PST” / “PDT” ;
Pacific: – 8/ – 7/ 1ALPHA ;
Military: Z = UT;
A:-1; (J not used);
M:-12;
N:+1;
Y:+12/ ( (“+” / “-“) 4DIGIT ) ; Local differential

这里面关于时区的概念很复杂可以是“+”或者“-”接后面四个数字,也可以是以上的这么多专用代码,大部分代表的是美国不同地区如东西部地区的时区字母缩写,整理一下就是就是:
EDT is 相等于 -0400
EST is 相等于 -0500
CDT is 相等于 -0500
CST is 相等于 -0600
MDT is 相等于 -0600
MST is 相等于 -0700
PDT is 相等于 -0700
PST is 相等于 -0800

编程思路

知道大概的思路之后,我们就开始着手进行编程,将rss的时间格式转化为标准时间格式:

1、分割字符串,由于以上的格式标准是用”,”和空格进行分割的,我们就利用其空格将其分割为5个字符串。

2、将分割的第二个字符串即月份从英文缩写格式转换为数字格式。

3、组合前四个字符串,格式化为标准时间。

4、处理第五个字符串即时区,计算应该加减的时间。

5、与组合的标准时间加减得到东八区的时间。

上图的最下面的时间已经转化为了东八区的标准时间

具体的代码如下,(注:此版本只处理了标准的时区格式,如有需要请自行再处理)


function StringToList(AText: string; Splitter: string): TStrings;
begin
  result := TStringList.Create;
  result.Text := StringReplace(AText, Splitter, sLineBreak, [rfReplaceAll]);
end;
function GetDate(AXmlDate: string): TDateTime;
var
  fDate: string;
  fYear, fMonth, fDay, fTime,fUtc: string;
  fList: TStrings;
  function GetMonth(AName: string): String;
  var
    fMonth: Integer;
  begin
    if AName = 'Jan' then fMonth := 1 else
    if AName = 'Feb' then fMonth := 2 else
    if AName = 'Mar' then fMonth := 3 else
    if AName = 'Apr' then fMonth := 4 else
    if AName = 'May' then fMonth := 5 else
    if AName = 'Jun' then fMonth := 6 else
    if AName = 'Jul' then fMonth := 7 else
    if AName = 'Aug' then fMonth := 8 else
    if AName = 'Sep' then fMonth := 9 else
    if AName = 'Oct' then fMonth := 10 else
    if AName = 'Nov' then fMonth := 11 else
    if AName = 'Dec' then fMonth := 12 else
      fMonth := 0;
    if (fMonth > 0) then
    begin
      result := IntTostr(fMonth);
      if (fMonth < 10) then
        result := '0' + IntTostr(fMonth);
    end;
  end;
begin
  if (AnsiPos(',', AXmlDate) > 0) or (AnsiPos('GMT', AXmlDate) > 0) then
  begin
    //The date format is :ddd, dd mmm yyyy hh:mm:ss zzz
    fDate := Copy(AXmlDate, AnsiPos(',', AXmlDate) + 1, Length(AXmlDate));
    fDate := Trim(fDate);
    fList := StringToList(fDate, #32);
    try
      if fList.Count >= 4 then
      begin
        fDay := fList[0];
        fMonth := GetMonth(fList[1]);
        fYear := fList[2];
        fTime := fList[3];
        fDate := Format('%s-%s-%s %s', [fyear, fMonth, fDay, fTime]);
        fUtc:= StringReplace(fList[4],'+','',[rfReplaceAll]);
        fUtc:= StringReplace(fUtc,'0','',[rfReplaceAll]);
        if fUtc='' then fUtc:='0';


        if (8-strtoint(fUtc))>=0 then
        begin
          fDate:=DateTimeToStr(strtodatetime(fdate)+strtodatetime(inttostr(8-strtoint(fUtc))+':00:00'));
        end
        else
        begin
          fDate:=DateTimeToStr(strtodatetime(fdate)-strtodatetime(inttostr(strtoint(fUtc)-8)+':00:00'));
        end;
      end;
    finally
      // free resources
      fList.Free;
    end;  // try/finally
  end
  else
    fDate := AXmlDate;
  result := StrToDateTime(fDate);
end;

吵吵微信朋友圈,请付款实名加入:

吵吵 吵吵

发表评论

电子邮件地址不会被公开。 必填项已用*标注