日期类型在浏览器与协议中的差异

日期类型在浏览器与协议中的差异

概述

我在本文前半部分主要是Javascript的日期类型的兼容性问题,后半部分主要是分析日期类型表现格式在不同协议中的差异。

JavaScript的日期类型的兼容性

最近在做一个项目中,使用了JavaScript来处理时间问题。用到的功能有两个:字符串与日期类型的相互转换,求两个日期的时间差。这么简单的功能,居然也因为浏览器对JavaScript实现的巨大差异,导致了兼容性问题。

日期类型转为字符串

JavaScript中Date类型转为字符串很简单,调用toString()方法就好了,但是结果有差异。
用简单的语句来测试下:

var date = new Date();  
console.log(date.toString());
浏览器 日期格式 协议
IE Thu Feb 8 16:31:08 UTC+0800 2018 RFC-850 / 1036
Fire Fox Thu Feb 08 2018 16:59:41 GMT+0800 RFC-822 / 1123
Chrome Thu Feb 08 2018 17:00:38 GMT+0800 (China Standard Time) RFC-822 / 1123
Safari Thu Feb 08 2018 17:00:38 GMT+0800 (CST) RFC-822 / 1123

由这个表可以看出,日期类型转换为字符串的格式除了IE使用 RFC-850 格式以外,都是 RFC-1123 格式。无论 RFC-850 格式,还是 RFC-1123 格式都是HTTP协议(RFC-2616)允许的日期格式。(具体协议内容,参见协议日期格式

在时区部分出现 GMTUTC 可以认为都代表的是标准时间(Universal Time),但是它们还是有差异的,其中细微的差别,参见ISO-19018 Terms, abbreviations, graphical symbols and concepts on navigation

字符串转换为日期类型

其实从上一节已经可以看出,浏览器自身是遵守了标准协议的日期格式,虽然稍有差异可都还处于可接受范围以内。但是当涉及到反向操作,即字符串转换为日期类型时,事情就没有这么简单。

标准协议允许的日期格式,在我看来并不怎么在日常生活中使用,完全是一种基于技术性的考虑定义的一种挺别扭的格式(至少我这么认为的)。另外除了IETF协议定义了日期格式以外,ISO也有关于日期格式的标准(ISO-8601 Representation of dates and times),再加上许多日常使用的格式,如何解析字符串是一个问题。

在高级语言中,解析日期字符串都是有专门的方法,也可以自己定义日期字符串的构成规则,这样很好的解决了解析中最头痛的格式问题。但是JavaScript的parse方法并没有提供自定义日期格式的功能,这一点点的缺陷就是浏览器日期解析兼容性问题的源头。

我编写了一段脚本,用来测试浏览器对此功能的兼容性,结果如下:

<html>
    <head>
      <meta charset="utf-8">
      <script type="text/javascript">
        function parse_str_to_date(dateString){
            return Date.parse(dateString);
        }
      </script> 
    </head>
    <body>
       <script type="text/javascript">
            var dateStrings = [
                "Thu Feb 08 2018 16:59:41 GMT+0800",    // RFC-822 (1123)
                "Thu Feb 8 16:31:08 UTC+0800 2018",     // RFC-850 (1036)
                "Thu 8-Feb-2018 16:31:08 UTC+0800 ",    // RFC-850 (1036)
                "2018-02-08T16:31:08+08:00",            // ISO-8601
                "2018-02-08 16:31:08+08:00",
                "2018-02-08 16:31:08 +08:00",
                "2018/02/08 16:31:08+08:00",
                "2018/02/08 16:31:08 +08:00",
                "2018-02-08 16:31:08",
                "18-02-08 16:31:08",
                "2018/02/08 16:31:08",
                "02/08/2018 16:31:08",
                "02/08/18 16:31:08"
            ];

            for (var i = 0; i < dateStrings.length; i++){
                var s = dateStrings[i];
                var dt = parse_str_to_date(s);
                var element = "";

                if (dt) element = "<p>" + s + " --> " + dt.toString() + "</p>";
                else element = "<p style='color:red'>" + s + " --> " + dt.toString() + "</p>";

                document.write(element);
            }
       </script>
    </body>
</html>  

执行结果如下:
Internet Explorer


Firefox


Chrome


Safari

可以看出,除IE以外的各主流浏览器对IETF和ISO协议的格式都能很好地支持,IE对RFC-850格式支持不完整。但对于非标准格式的支持度有不小的差异。Chrome的兼容性最好,IE的兼容性最差,而且有两种格式数据解析错误。

协议日期格式

关于日期格式的协议大致分为IETF的RFC协议 和 ISO组织的ISO标准:

  1. RFC-850 / 1036
    RFC-850 / 1036中规定的日期格式有三种:
    Weekday, DD-Mon-YY HH:MM:SS TIMEZONE
    Wdy Mon DD HH:MM:SS YYYY
    Wdy, DD Mon YY HH:MM:SS TIMEZONE

  2. RFC-822 / 1123
    RFC-822 / 1123中规定的日期格式为:
    [Wdy,] DD Mon YYYY HH:MM:SS TIMEZONE

  3. RFC-2616
    RFC-2616中没有规定自己的格式,它允许的格式包括:RFC-850格式、RFC-1123格式和 asctime()格式。

  4. RFC-2822
    RFC-2822中规定的日期格式基本与 RFC-1123 相同。只是在TimeZone没有要求写出时区名字。

  5. ISO-8601
    ISO-8601中规定的日期格式很全面,分为 Calendar DateOrdinal DateWeek Date三种,每一种还细分为Basic FormatExtended Format两种格式。
    Basic FormatExtended Format的差异是Basci Formt没有年月日以及时分秒之间的分隔符。
    time designator表示为’T’,zone designator如果是零时区,表示为’Z’,其他时区表示为’+|-zzzz’,week designator表示为’W’。
    如果觉得看英文比较头痛的话,可以参见 国家标准 GB/T 7408-2005。它基本上就是ISO-8601的中文翻译版。

    • For calendar dates:
      year – month – day of the month – time designator – hour – minute – second – zone designator
    • For ordinal dates:
      year – day of the year – time designator – hour – minute – second – zone designator
    • For week dates:
      year – week designator – week – day of the week – time designator – hour – minute – second – zone designator

附录

  • RFC-2616 - Hypertext Transfer Protocol – HTTP/1.1

    3.3 Date/Time Formats

    3.3.1 Full Date

    HTTP applications have historically allowed three different formats for the representation of date/time stamps:

    Sun, 06 Nov 1994 08:49:37 GMT ; RFC 822, updated by RFC 1123
    Sunday, 06-Nov-94 08:49:37 GMT ; RFC 850, obsoleted by RFC 1036
    Sun Nov 6 08:49:37 1994 ; ANSI C’s asctime() format

    The first format is preferred as an Internet standard and represents a fixed-length subset of that defined by RFC 1123 [8] (an update to RFC 822 [9]). The second format is in common use, but is based on the obsolete RFC 850 [12] date format and lacks a four-digit year. HTTP/1.1 clients and servers that parse the date value MUST accept all three formats (for compatibility with HTTP/1.0), though they MUST only generate the RFC 1123 format for representing HTTP-date values in header fields. See section 19.3 for further information.

    Note: Recipients of date values are encouraged to be robust in accepting date values that may have been sent by non-HTTP applications, as is sometimes the case when retrieving or postingmessages via proxies/gateways to SMTP or NNTP.

    All HTTP date/time stamps MUST be represented in Greenwich Mean Time (GMT), without exception. For the purposes of HTTP, GMT is exactly equal to UTC (Coordinated Universal Time). This is indicated in the first two formats by the inclusion of “GMT” as the three-letter abbreviation for time zone, and MUST be assumed when reading the asctime format. HTTP-date is case sensitive and MUST NOT include additional LWS beyond that specifically included as SP in the grammar.

          HTTP-date    = rfc1123-date | rfc850-date | asctime-date
          rfc1123-date = wkday "," SP date1 SP time SP "GMT"
          rfc850-date  = weekday "," SP date2 SP time SP "GMT"
          asctime-date = wkday SP date3 SP time SP 4DIGIT
          date1        = 2DIGIT SP month SP 4DIGIT
                        ; day month year (e.g., 02 Jun 1982)
          date2        = 2DIGIT "-" month "-" 2DIGIT
                        ; day-month-year (e.g., 02-Jun-82)
          date3        = month SP ( 2DIGIT | ( SP 1DIGIT ))
                        ; month day (e.g., Jun  2)
          time         = 2DIGIT ":" 2DIGIT ":" 2DIGIT
                        ; 00:00:00 - 23:59:59
          wkday        = "Mon" | "Tue" | "Wed"
                      | "Thu" | "Fri" | "Sat" | "Sun"
          weekday      = "Monday" | "Tuesday" | "Wednesday"
                      | "Thursday" | "Friday" | "Saturday" | "Sunday"
          month        = "Jan" | "Feb" | "Mar" | "Apr"
                      | "May" | "Jun" | "Jul" | "Aug"
                      | "Sep" | "Oct" | "Nov" | "Dec"
    

    Note: HTTP requirements for the date/time stamp format apply only to their usage within the protocol stream. Clients and servers are not required to use these formats for user presentation, request logging, etc.

  • RFC-822 Standard for ARPA Internet Text Messages

    5 DATE AND TIME SPECIFICATION

    5.1. SYNTAX

          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<br/>
                      /  "EST" / "EDT"                ;  Eastern:  - 5/ - 4<br/>
                      /  "CST" / "CDT"                ;  Central:  - 6/ - 5<br/>
                      /  "MST" / "MDT"                ;  Mountain: - 7/ - 6<br/>
                      /  "PST" / "PDT"                ;  Pacific:  - 8/ - 7<br/>
                      /  1ALPHA                       ; Military: Z = UT;
                                                       ;  A:-1; (J not used)
                                                        ;  M:-12; N:+1; Y:+12<br/>
                      / ( ("+" / "-") 4DIGIT )        ; Local differential
                                                      ;  hours+min. (HHMM)<br/>
    

    5.2. SEMANTICS

    If included, day-of-week must be the day implied by the date specification.

    Time zone may be indicated in several ways. “UT” is Universal Time (formerly called “Greenwich Mean Time”); “GMT” is permitted as a reference to Universal Time. The military standard uses a single character for each zone. “Z” is Universal Time. “A” indicates one hour earlier, and “M” indicates 12 hours earlier; “N” is one hour later, and “Y” is 12 hours later. The letter “J” is not used. The other remaining two forms are taken
    from ANSI standard X3.51-1975. One allows explicit indication of the amount of offset from UT; the other uses common 3-character strings for indicating time zones in North America.

  • RFC-1123 Requirements for Internet Hosts – Application and Support

    5.2.14 RFC-822 Date and Time Specification: RFC-822 Section 5

    The syntax for the date is hereby changed to:

      date = 1*2DIGIT month 2*4DIGIT
    

    All mail software SHOULD use 4-digit years in dates, to ease the transition to the next century.

    There is a strong trend towards the use of numeric timezone indicators, and implementations SHOULD use numeric timezones instead of timezone names. However, all implementations MUST
    accept either notation. If timezone names are used, they MUST be exactly as defined in RFC-822.

    The military time zones are specified incorrectly in RFC-822: they count the wrong way from UT (the signs are reversed). As a result, military time zones in RFC-822 headers carry no
    information.

  • RFC-850 Standard for Interchange of USENET Messages

    2.1.4 Date The Date line (formerly “Posted”) is the date, in a format that must be acceptable both to the ARPANET and to the getdate routine, that the article was originally posted to the network. This date remains unchanged as the article is propagated throughout the network. One format that is acceptable to both is

     Weekday, DD-Mon-YY HH:MM:SS TIMEZONE
    

    Several examples of valid dates appear in the sample article above. Note in particular that ctime format:

     Wdy Mon DD HH:MM:SS YYYY
    

    is not acceptable because it is not a valid ARPANET date. However, since older software still generates this format, news implementations are encouraged to accept this format
    and translate it into an acceptable format.

    The contents of the TIMEZONE field is currently subject tow orldwide time zone abbreviations, including the usual American zones (PST, PDT, MST, MDT, CST, CDT, EST, EDT), the other North American zones (Bering through Newfoundland), European zones, Australian zones, and so on. Lacking a complete list at present (and unsure if an
    unambiguous list exists), authors of software are encouraged to keep this code flexible, and in particular not to assume that time zone names are exactly three
    letters long. Implementations are free to edit this field, keeping the time the same, but changing the time zone (with an appropriate adjustment to the local time
    shown) to a known time zone.

  • RFC-1036 Standard for Interchange of USENET Messages

    2.1.2. Date
    The “Date” line (formerly “Posted”) is the date that the message was originally posted to the network. Its format must be acceptable both in RFC-822 and to the getdate(3) routine that is provided with the Usenet software. This date remains unchanged as the message is
    propagated throughout the network. One format that is acceptable to both is:

     Wdy, DD Mon YY HH:MM:SS TIMEZONE
    

    Several examples of valid dates appear in the sample message above. Note in particular that ctime(3) format:

     Wdy Mon DD HH:MM:SS YYYY
    

    is not acceptable because it is not a valid RFC-822 date. However, since older software still generates this format, news implementations are encouraged to accept this format and translate it into an acceptable format.

    There is no hope of having a complete list of timezones. Universal Time (GMT), the North American timezones (PST, PDT, MST, MDT, CST, CDT, EST, EDT) and the +/-hhmm offset specifed in RFC-822 should be supported. It is recommended that times in message headers be transmitted in GMT and displayed in the local time zone.

  • RFC-2822 Internet Message Format

    3.3. Date and Time Specification

    Date and time occur in several header fields. This section specifies the syntax for a full date and time specification. Though folding white space is permitted throughout the date-time specification, it is RECOMMENDED that a single space be used in each place that FWS
    appears (whether it is required or optional); some older implementations may not interpret other occurrences of folding white space correctly.

       date-time       =       [ day-of-week "," ] date FWS time [CFWS]
    
       day-of-week     =       ([FWS] day-name) / obs-day-of-week
    
       day-name        =       "Mon" / "Tue" / "Wed" / "Thu" /
                           "Fri" / "Sat" / "Sun"
    
       date            =       day month year
    
       year            =       4*DIGIT / obs-year
    
       month           =       (FWS month-name FWS) / obs-month
    
       month-name      =       "Jan" / "Feb" / "Mar" / "Apr" /
                           "May" / "Jun" / "Jul" / "Aug" /
                           "Sep" / "Oct" / "Nov" / "Dec"
    
       day             =       ([FWS] 1*2DIGIT) / obs-day
    
       time            =       time-of-day FWS zone
    
       time-of-day     =       hour ":" minute [ ":" second ]
    
       hour            =       2DIGIT / obs-hour
    
       minute          =       2DIGIT / obs-minute
    
       second          =       2DIGIT / obs-second
    
       zone            =       (( "+" / "-" ) 4DIGIT) / obs-zone
    

    The day is the numeric day of the month. The year is any numeric year 1900 or later.

    The time-of-day specifies the number of hours, minutes, and optionally seconds since midnight of the date indicated.

    The date and time-of-day SHOULD express local time.

    The zone specifies the offset from Coordinated Universal Time (UTC, formerly referred to as “Greenwich Mean Time”) that the date and time-of-day represent. The “+” or “-” indicates whether the time-of-day is ahead of (i.e., east of) or behind (i.e., west of) Universal Time. The first two digits indicate the number of hours difference from Universal Time, and the last two digits indicate the number of minutes difference from Universal Time. (Hence, +hhmm means +(hh * 60 + mm) minutes, and -hhmm means -(hh * 60 + mm) minutes). The form “+0000” SHOULD be used to indicate a time zone at Universal Time. Though “-0000” also indicates Universal Time, it is used to indicate that the time was generated on a system that may be in a local time zone other than Universal Time and therefore indicates that the date-time contains no information about the local time zone.

    A date-time specification MUST be semantically valid. That is, the day-of-the-week (if included) MUST be the day implied by the date, the numeric day-of-month MUST be between 1 and the number of days allowed for the specified month (in the specified year), the time-of-day MUST be in the range 00:00:00 through 23:59:60 (the number of seconds allowing for a leap second; see [STD12]), and the zone MUST be within the range -9959 through +9959.

  • ISO-8601 Representation of dates and times

    4.3 Date and time of day

    4.3.1 General

    When the application does not clearly identify the need for only a date expression (see 4.1) or only a time of day expression (see 4.2), then a time point can be identified through a date and time of day expression.

    4.3.2 Complete representations

    The time elements of a date and time of day expression shall be written in the following sequence.

    a) For calendar dates:

    year – month – day of the month – time designator – hour – minute – second – zone designator
    

    b) For ordinal dates:

    year – day of the year – time designator – hour – minute – second – zone designator
    

    c) For week dates:

    year – week designator – week – day of the week – time designator – hour – minute – second – zone designator
    

    The zone designator is empty if use is made of local time in accordance with 4.2.2.2 through 4.2.2.4, it is the UTC designator [Z] if use is made of UTC of day in accordance with 4.2.4 and it is the difference-component if use is made of local time and the difference from UTC in accordance with 4.2.5.2.

    The character [T] shall be used as time designator to indicate the start of the representation of the time of day component in these expressions. The hyphen [-] and the colon [:] shall be used, in accordance with 4.4.4, as separators within the date and time of day expressions, respectively, when required.

    NOTE By mutual agreement of the partners in information interchange, the character [T] may be omitted in applications where there is no risk of confusing a date and time of day representation with others defined in this International Standard.

    The following are examples of complete representations of date and time of day representations:

    Basic format: YYYYMMDDThhmmss
    YYYYMMDDThhmmssZ
    YYYYMMDDThhmmss±hhmm
    YYYYMMDDThhmmss±hh
    Example: 19850412T101530
    19850412T101530Z
    19850412T101530+0400
    19850412T101530+04
    Extended format: YYYY-MM-DDThh:mm:ss
    YYYY-MM-DDThh:mm:ssZ
    YYYY-MM-DDThh:mm:ss±hh:mm
    YYYY-MM-DDThh:mm:ss±hh
    Example: 1985-04-12T10:15:30
    1985-04-12T10:15:30Z
    1985-04-12T10:15:30+04:00
    1985-04-12T10:15:30+04

    Where complete representations using calendar dates are shown, ordinal dates (4.1.3.2) or week dates (4.1.4.2) may be substituted.

猜你喜欢

转载自blog.csdn.net/rocket2002/article/details/79304434