JavaScriptカスタム日付フォーマット関数


私たちはJavaScriptに対してその中の一つの一般的なやり方を拡張します.Date.prototypeの拡張です.Dateクラスは日付要素を取得する方法だけを提供していることを知っています.例えば、getDate()、getMinute()......特定の文字列に変換するフォーマット方法はありません.ですから、これらの細かい方法を利用してパッケージ化して、私たちが欲しい日付文字列の形を組み合わせます.一般的には、このフォーマット関数は、Dateオブジェクトの原型に定義されても良いし、独立して一つの方法で書き出すこともできます.原型を定義する方法の操作は、Date.prototype.format=function{…}のように、直接new Date().format(YYYY:MM:DD)を使ってもいいです.しかし、プロトタイプの定義方法は、JSプロトタイプの「侵入」がやや不足しています.APIを設計する時はこの問題を考慮しなければならない.私の提案は、ユーザーが自分の判断によって決定します.呼び出しの方式が違っていて、過程のロジックに影響しないだけでいいです.
次の例は独立関数で書かれたJavaScript日付フォーマット関数で、独立したformat関数です.フォーマットに戻るという知識点では、どのように実現され、どのような原理が使われているかを検討しています.従来の文字列スティッチングはindexOf()+substr()のように実現できますが、明らかに効率が低いだけでなく、コードが長いだけでなく、正規表現を導入する方法に適しています.まず文字列の正規表現を書いてから結果の命中マッチングを行います.まず、Steven Levithanからの例を見ます.
 
   /**
     * Date Format 1.2.3
     * @credit Steven Levithan <stevenlevithan.com> Includes enhancements by Scott Trenda <scott.trenda.net> and Kris Kowal <cixar.com/~kris.kowal/>
     * Accepts a date, a mask, or a date and a mask.
     * Returns a formatted version of the given date.
     * The date defaults to the current date/time.
     * The mask defaults to dateFormat.masks.default.
     */  
    dateFormat = (function(){  
        //     , 1、token,(?:)       ;/1     (  :{1,2}   /1    ?);       [LloSZ]                ,   ,      /L|l|o|S|Z/         ;     “ ”            (          )。  
        var token        = /d{1,4}|m{1,4}|yy(?:yy)?|([HhMsTt])/1?|[LloSZ]|"[^"]*"|'[^']*'/g,  
        // 2、timezone, [PMCEA][SDP]         ; reg        ,       。  
            timezone     = //b(?:[PMCEA][SDP]T|(?:Pacific|Mountain|Central|Eastern|Atlantic) (?:Standard|Daylight|Prevailing) Time|(?:GMT|UTC)(?:[-+]/d{4})?)/b/g,  
            timezoneClip = /[^-+/dA-Z]/g,  
              
            //         ,        
            pad          = function (val, len){  
                val = String(val);  
                len = len || 2;  
                while (val.length < len) val = "0" + val;  
                return val;  
            };  
        //        function,              ,                  。             。       ,    。  
        // Regexes and supporting functions are cached through closure  
        //     :date: Date           ;mask:String         ;utc:Stirng    UTC。  
        return function (date, mask, utc) {  
            var i18n  = dateFormat.i18n;  
            var masks = dateFormat.masks;  
            // You can't provide utc if you skip other args (use the "UTC:" mask prefix)  
            //         ,              ,        mask。date    if  new Date  ,  date       。  
            if (arguments.length == 1 && Object.prototype.toString.call(date) == "[object String]" && !//d/.test(date)) {  
                mask = date;  
                date = undefined;  
            }  
              
            // Passing date through Date applies Date.parse, if necessary  
            date = date ? new Date(date) : new Date;  
            if (isNaN(date)) throw SyntaxError("invalid date");  
            //           mask   ,          。   ||    。  
            mask = String(masks[mask] || mask || masks["default"]);  
            // Allow setting the utc argument via the mask  
            if (mask.slice(0, 4) == "UTC:") {  
                mask = mask.slice(4);  
                utc = true;  
            }  
            //      , UTC         。    JS               。  
            var _ = utc ? "getUTC" : "get",  
                d = date[_ + "Date"](),  
                D = date[_ + "Day"](),  
                m = date[_ + "Month"](),  
                y = date[_ + "FullYear"](),  
                H = date[_ + "Hours"](),  
                M = date[_ + "Minutes"](),  
                s = date[_ + "Seconds"](),  
                L = date[_ + "Milliseconds"](),  
                o = utc ? 0 : date.getTimezoneOffset(),  
                flags = {  
                    d:    d,  
                    dd:   pad(d),  
                    ddd:  i18n.dayNames[D],  
                    dddd: i18n.dayNames[D + 7],//   :7,   dateFormat.dayNames。  
                    m:    m + 1, //  0       
                    mm:   pad(m + 1),  
                    mmm:  i18n.monthNames[m],  
                    mmmm: i18n.monthNames[m + 12], //   :12,  dateFormat.monthNames  
                    yy:   String(y).slice(2),//    slice()     
                    yyyy: y,  
                    h:    H % 12 || 12, // h  12   ,h  12(      ),      12    。  
                    hh:   pad(H % 12 || 12),  
                    H:    H,  
                    HH:   pad(H),  
                    M:    M,  
                    MM:   pad(M),  
                    s:    s,  
                    ss:   pad(s),  
                    l:    pad(L, 3), // Max,999ms  
                    L:    pad(L > 99 ? Math.round(L / 10) : L),  
                    //         
                    t:    H < 12 ? "a"  : "p",  
                    tt:   H < 12 ? "am" : "pm",  
                    T:    H < 12 ? "A"  : "P",  
                    TT:   H < 12 ? "AM" : "PM",  
                    //      timezone,       。  
                    //    timezone,timezoneClip = /[^-+/dA-Z]/g,  
                    // String          ,     ……UTC……    
                    //     , [""].pop()        
                    Z:    utc ? "UTC" : (String(date).match(timezone) || [""]).pop().replace(timezoneClip, ""),  
                    // 4  TimezoneOffset  
                    o:    (o > 0 ? "-" : "+") + pad(Math.floor(Math.abs(o) / 60) * 100 + Math.abs(o) % 60, 4),  
                    //     ["th", "st", "nd", "rd"],   d      
                    S:    ["th", "st", "nd", "rd"][d % 10 > 3 ? 0 : (d % 100 - d % 10 != 10) * d % 10]  
                };  
            return mask.replace(token, function ($0 /*  $0,  $1、$2      */) {  
                //                 ?  in     !  
                // $0.slice(1, $0.length - 1);?    ?  
                return $0 in flags ? flags[$0] : $0.slice(1, $0.length - 1);  
            });  
        };  
    })();  
この部分のコードは日付処理に対して周到に考慮しています.原理を見てみます.――日付をどう処理しますか?
日付文字列テンプレートでは、y y y/m m/d dなどの意味のある記号で日付の中のある要素をそれぞれ表すことを約束しています.yはyearのある年、mはmonthのある月、dはdayのある日、大文字である場合は区別に注意してください.大文字Mは分、小文字は月です.つまり、これは私達が人為的に決められた約束です.つまり上記のコードのいわゆる「mask」は、この約束に従ってフォーマットモードのパラメータを入力したいなら、日付タイプの値を印刷可能な文字列に出力することができます.解析の日時過程は、まずMaskのすべての要求に従って、日付の各要素(getDate()、getMinute()、そしてMaskの本当の条件は何ですか?すなわちMask.replace(正則、元素)の方法によって文字列テンプレートと要素の間の置き換えが行われます.置換の過程は、flageを一つの対照表とします.正則部分については,tokenとreplace()関数を理解する過程が鍵となる.上記のコードのコメントに参加すれば、内部の詳細が分かります.
毎回長いMask文字列を入力すると大変ですか?私たちは定数を定義する方法で私たちの仕事量を減らすことができます.
 
  dateFormat.masks = {  
        "default":      "ddd mmm dd yyyy HH:MM:ss",  
        shortDate:      "m/d/yy",  
        shortDate2:     "yy/m/d/h:MM:ss",  
        mediumDate:     "mmm d, yyyy",  
        longDate:       "mmmm d, yyyy",  
        fullDate:       "dddd, mmmm d, yyyy",  
        shortTime:      "h:MM TT",  
        mediumTime:     "h:MM:ss TT",  
        longTime:       "h:MM:ss TT Z",  
        isoDate:        "yyyy-mm-dd",  
        isoTime:        "HH:MM:ss",  
        isoDateTime:    "yyyy-mm-dd'T'HH:MM:ss",  
        isoUtcDateTime: "UTC:yyyy-mm-dd'T'HH:MM:ss'Z'"  
        //           @Edit 2010.8.11  
        ,ChineseDate   :'yyyy mm dd  HH MM '  
    }  
          
    dateFormat.i18n = {  
        dayNames: [  
            "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat",  
            "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"  
        ],  
        monthNames: [  
            "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec",  
            "January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"  
        ]  
    };  
SteveのdateFormatは大多数の期日の転化の任務を完成することができますが、広大なコードの中で、より優れた解法を見つけました.
  
Date.prototype.format = function(format) //author: meizz  
    {  
      var o = {  
        "M+" : this.getMonth()+1, //month  
        "d+" : this.getDate(),    //day  
        "h+" : this.getHours(),   //hour  
        "m+" : this.getMinutes(), //minute  
        "s+" : this.getSeconds(), //second  
        "q+" : Math.floor((this.getMonth()+3)/3),  //quarter  
        "S" : this.getMilliseconds() //millisecond  
      }  
      if(/(y+)/.test(format)) format=format.replace(RegExp.$1,  
        (this.getFullYear()+"").substr(4 - RegExp.$1.length));  
      for(var k in o)if(new RegExp("("+ k +")").test(format))  
        format = format.replace(RegExp.$1,  
          RegExp.$1.length==1 ? o[k] :  
            ("00"+ o[k]).substr((""+ o[k]).length));  
      return format;  
    }  
    alert(new Date().format("yyyy-MM-dd hh:mm:ss"));  
原理的にはSteve方法と似ていますが、より濃縮されたコードは技術性と全面性を備えています.ソース12行目からスタートして、test()メソッドは、この最低限の機能にマッチするかどうかを検出することができますし、実際には、メモリマッチングの結果、RegExp.$1の結果グループが生成されます.そして、new RegExpによって文字列形式で正規表現を作成する例は、また優れたところである.――直接にoのhashテーブルとドッキングしたからである.続いて瓢箪に基づいて、まず的中かどうかをテストします.
また、コードの中の(「00」+o[k]).substr(String(o[k].length)も面白いところですが、前に二つを加えてどういう意味ですか?本来の目的は配列の最後の二桁を取るためです.これはsubstr()方法を総合的に利用する技法であり、substrの最初のパラメータは切り取りを開始するindexであり、第二のパラメータindexを指定しないと文字列を最後まで保持する.そこで、私たちは事前に何位か追加しましたが、元々固定されていた文字列の長さが変わらない場合は、いくつかのビットを残します.(p.s「00」はプレースホルダに相当します.他の文字列「XX」でも大丈夫です.)
このコードには多くの困難があると思いますか?私達は月影の関数を可読性の強いコードに書き直してみました.原理的には一致していますが、そんなに多くの技術がないです.これはみんなの時間を節約できると信じています.後で月影のコードを見に行きます.
  
date = {  
        format: function(date, format){  
            date = new Date(date); // force con.  
            date = {  
                 year   : date.getFullYear()  
                ,month  : date.getMonth() + 1 //   ,         
                ,day    : date.getDate()  
                ,hour   : date.getHours()  
                ,minute : date.getMinutes()  
                ,second : date.getSeconds()  
                ,milute : date.getMilliseconds()  
            };  
            var   
                 match  
                ,reg = /(y+)|(Y+)|(M+)|d+|h+|m+|s+|u+/g;  
            while((match = reg.exec(format)) != null){  
                match = match[0];  
                if(/y/i.test(match)){  
                    format = format.replace(match, date.year);  
                }  
                if(match.indexOf('M') != -1){  
                    format = format.replace(match, date.month);  
                }  
                if(match.indexOf('d') != -1){  
                    format = format.replace(match, date.day);  
                }                 
                if(match.indexOf('h') != -1){  
                    format = format.replace(match, date.hour);  
                }  
                if(match.indexOf('m') != -1){  
                    format = format.replace(match, date.minute);  
                }     
                if(match.indexOf('s') != -1){  
                    format = format.replace(match, date.second);  
                }   
                if(match.indexOf('u') != -1){  
                    format = format.replace(match, date.milute);  
                }                             
            }  
            return format;  
        }  
    };  

2011--1-7:
ext 4.0から取り除かれた日付書式のコードは、文字列がjs標準日付に変わりますか?新しいextはどうやって作ったのか見てください.
 
   /**
     *               。
     * Parse a value into a formatted date using the specified format pattern.
     * @param {String/Date} value       (       JavaScript         ,  <a href="http://www.w3schools.com/jsref/jsref_parse.asp" mce_href="http://www.w3schools.com/jsref/jsref_parse.asp">parse()</a>)The value to format (Strings must conform to the format expected by the javascript  
     * Date object's <a href="http://www.w3schools.com/jsref/jsref_parse.asp" mce_href="http://www.w3schools.com/jsref/jsref_parse.asp">parse()</a> method)
     * @param {String} format (   )           。(   'm/d/Y')(optional) Any valid date format string (defaults to 'm/d/Y')
     * @return {String}        。The formatted date string
     */  
    date: function(v, format) {  
        if (!v) {  
            return "";  
        }  
        if (!Ext.isDate(v)) {  
            v = new Date(Date.parse(v));  
        }  
        return v.dateFormat(format || Ext.util.Format.defaultDateFormat);  
    }  
ダテコンストラクタはまた、1970からどのぐらいのミリ秒数を算出することによって日付を決定することができますか?確かに、このようにしてもいいです.――つまり、一挙一反対して、この問題から、js日付が一番小さい単位はミリ秒です.