【DateFormat】String-(parse)->Date、Date-(format)->String

by wetcradle
【DateFormat】String-(parse)->Date、Date-(format)->String

昔、mx.formatters.DateFormatterの存在に気付かずに、
自作したDateFormatというクラス。
せっかくなので、晒してみた。
♥0 | Line 270 | Modified 2010-05-12 00:12:30 | MIT License
play

ActionScript3 source code

/**
 * Copyright wetcradle ( http://wonderfl.net/user/wetcradle )
 * MIT License ( http://www.opensource.org/licenses/mit-license.php )
 * Downloaded from: http://wonderfl.net/c/lvUO
 */

/**
昔、mx.formatters.DateFormatterの存在に気付かずに、
自作したDateFormatというクラス。
せっかくなので、晒してみた。
*/

package {
	import flash.display.Sprite;
	import flash.text.TextField;
	public class FlashTest extends Sprite {
		public function FlashTest() {
			var textField:TextField = new TextField();
			textField.width = textField.height = 400;
			addChild(textField);
			
			var dateFormat:DateFormat = new DateFormat();
			
			dateFormat.format = "YY年MM月DD日 H時N分S秒";
			textField.appendText(dateFormat.formatDate(new Date())+"\n");
			
			dateFormat.format = "YYYY-M-D H:N:S";
			textField.appendText(String(dateFormat.parseString("2009-12-24 1:23:4"))+"\n");
			
			//HHとフォーマット指定している場合は、時間は01を与えなければならない。
			//よって解析失敗となり結果はnullとなる。
			dateFormat.format = "YYYY-M-D HH:NN:SS";
			textField.appendText(dateFormat.parseString("2009-12-24 1:23:4")+"\n");
			
			//-と/が異なっているのでnullとなる
			dateFormat.format = "YYYY-M-D H:N:S";
			textField.appendText(String(dateFormat.parseString("2009/12/24 1:23:4")));
		}
	}
}

/**
Dateのインスタンスからフォーマットに従った文字列を生成します。
また、文字列をフォーマットに従い解析してDateのインスタンスを生成します。

使用可能なパターン
<table border="1">

<tr>
<td rowspan="2">年</td>
<td>YYYY</td>
<td>4桁。必要があれば0で埋める。</td>
</tr>
<tr>
<td>YY</td>
<td>下2桁。必要があれば0で埋める。</td>
</tr>

<tr>
<td rowspan="2">月</td>
<td>MM</td>
<td>2桁。必要があれば0で埋める。</td>
</tr>
<tr>
<td>M</td>
<td>1桁か2桁。</td>
</tr>

<tr>
<td rowspan="2">日</td>
<td>DD</td>
<td>2桁。必要があれば0で埋める。</td>
</tr>
<tr>
<td>D</td>
<td>1桁か2桁。</td>
</tr>

<tr>
<td rowspan="2">時</td>
<td>HH</td>
<td>2桁。必要があれば0で埋める。</td>
</tr>
<tr>
<td>H</td>
<td>1桁か2桁。</td>
</tr>

<tr>
<td rowspan="2">分</td>
<td>NN</td>
<td>2桁。必要があれば0で埋める。</td>
</tr>
<tr>
<td>N</td>
<td>1桁か2桁。</td>
</tr>

<tr>
<td rowspan="2">秒</td>
<td>SS</td>
<td>2桁。必要があれば0で埋める。</td>
</tr>
<tr>
<td>S</td>
<td>1桁か2桁。</td>
</tr>

</table>

例 YYYY/MM/DD HH:NN:SS
*/
class DateFormat {
	
	protected var _format:String;
	
	////////////////////////////////////////////////////////////
	//////////////コンストラクタ
	////////////////////////////////////////////////////////////
	
	//______________ DateFormat ______________//
	public function DateFormat(format:String="YYYY-M-D"):void {
		_format = format;
	}
	
	////////////////////////////////////////////////////////////
	//////////////プロパティ
	////////////////////////////////////////////////////////////
	
	//______________ format ______________//
	public function get format():String {
		return _format
	}
	public function set format(value:String):void {
		_format = value;
	}
	
	////////////////////////////////////////////////////////////
	//////////////パブリックメソッド
	////////////////////////////////////////////////////////////
	
	//______________ formatDate ______________//
	public function formatDate(date:Date, utc:Boolean=false):String {
		var year:int = utc ? date.fullYearUTC : date.fullYear;
		var month:int = utc ? date.monthUTC+1 : date.month+1;
		var tempDate:int = utc ? date.dateUTC : date.date;
		var hours:int = utc ? date.hoursUTC : date.hours;
		var minutes:int = utc ? date.minutesUTC : date.minutes;
		var seconds:int = utc ? date.secondsUTC : date.seconds;
		
		var string:String = _format;
		var yyyy:String = (year < 10) ? "000"+year :
		(year < 100) ? "00"+year :
		(year < 1000) ? "0"+year :
		String(year);
		string = string.replace(/YYYY/g, yyyy);
		string = string.replace(/YY/g, yyyy.substr(2, 2));
		
		var mm:String = (month < 10) ? "0"+String(month) : String(month);
		string = string.replace(/MM/g, mm);
		string = string.replace(/M/g, String(month));
		
		var dd:String = (tempDate < 10) ? "0"+tempDate : String(tempDate);
		string = string.replace(/DD/g, dd);
		string = string.replace(/D/g, String(tempDate));
		
		var hh:String = (hours < 10) ? "0"+hours : String(hours);
		string = string.replace(/HH/g, hh);
		string = string.replace(/H/g, String(hours));
		
		var nn:String = (minutes < 10) ? "0"+minutes : String(minutes);
		string = string.replace(/NN/g, nn);
		string = string.replace(/N/g, String(minutes));
		
		var ss:String = (seconds < 10) ? "0"+seconds : String(seconds);
		string = string.replace(/SS/g, ss);
		string = string.replace(/S/g, String(seconds));
		
		return string;
	}
	
	//______________ parseString ______________//
	/**
	stringをフォーマットに従い解析してDateのインスタンスを生成します。
	解析に失敗した時はnullを返します。
	utcがfalseのときはローカル時間、trueのときは世界時として解析します。
	*/
	public function parseString(string:String, utc:Boolean=false):Date {
		//trace(this+": parseString: string="+string);
		var year:int = 1970;
		var month:int = 1;
		var date:int = 1;
		var hours:int = 0;
		var minutes:int = 0;
		var seconds:int = 0;
		
		var i:int;//_formatを解析している位置
		var j:int = 0;//lastPatternの開始位置にあたるstringにおける位置
		var pattern:String = "";//最長前方一致
		var lastPattern:String = "";//最長完全一致
		for (i=0; i<_format.length; i++) {
			var char:String = _format.substr(i, 1);
			if (pattern) {
				if (isHeadOfPattern(pattern+char)) {
					pattern += char;
					if (isPattern(pattern)) {
						lastPattern = pattern;
					}
				}
				else {
					if (lastPattern) {
						parsePattern(lastPattern);
						lastPattern = "";
					}
					else {
						//解析失敗
						return null;
					}
					if (isHeadOfPattern(char)) {
						pattern = char;
						if (isPattern(pattern)) {
							lastPattern = pattern;
						}
					}
					else {
						pattern = "";
						if (char != string.substr(j, 1)) {
							return null;
						}
						j++;
					}
				}
			}
			else {
				if (isHeadOfPattern(char)) {
					pattern = char;
					if (isPattern(pattern)) {
						lastPattern = pattern;
					}
				}
				else {
					if (char != string.substr(j, 1)) {
						return null;
					}
					j++;
				}
			}
		}
		if (lastPattern) {
			parsePattern(lastPattern);
		}
		
		if (j > string.length) {
			return null;
		}
		var newDate:Date = new Date();
		if (utc) {
			newDate.fullYearUTC = year;
			newDate.monthUTC = month - 1;
			newDate.dateUTC = date;
			newDate.hoursUTC = hours;
			newDate.minutesUTC = minutes;
			newDate.secondsUTC = seconds;
		}
		else {
			newDate.fullYear = year;
			newDate.month = month - 1;
			newDate.date = date;
			newDate.hours = hours;
			newDate.minutes = minutes;
			newDate.seconds = seconds;
		}
		return newDate;
		
		//patternはパターンのいずれかでなければならない
		//
		function parsePattern(pattern:String):void {
			//trace(this+": parsePattern: pattern="+pattern+", i="+i+", j="+j);
			switch (pattern) {
			case "YYYY":
				year = int(string.substr(j, 4));
				j += 4;
				break;
			case "YY":
				var nowYear:int = utc ? new Date().fullYearUTC : new Date().fullYear;
				var yy:int = int(string.substr(j, 2));
				if (yy >= (nowYear - 90) % 100) {
					year = (int(nowYear / 100) - 1) * 100 + yy;
				}
				else {
					year = int(nowYear / 100) * 100 + yy;
				}
				j += 2;
				break;
			case "MM":
				month = int(string.substr(j, 2));
				j += 2;
				break;
			case "M":
				if (string.substr(j, 2).match(/\d\d/)) {
					month = int(string.substr(j, 2));
					if (month <= 12) {
						j += 2;
						break;
					}
				}
				month = int(string.substr(j, 1));
				j++;
				break;
			case "DD":
				date = int(string.substr(j, 2));
				j += 2;
				break;
			case "D":
				if (string.substr(j, 2).match(/\d\d/)) {
					date = int(string.substr(j, 2));
					if (date <= 31) {
						j += 2;
						break;
					}
				}
				date = int(string.substr(j, 1));
				j++;
				break;
			case "HH":
				hours = int(string.substr(j, 2));
				j += 2;
				break;
			case "H":
				if (string.substr(j, 2).match(/\d\d/)) {
					hours = int(string.substr(j, 2));
					if (hours <= 23) {
						j += 2;
						break;
					}
				}
				hours = int(string.substr(j, 1));
				j++;
				break;
			case "NN":
				minutes = int(string.substr(j, 2));
				j += 2;
				break;
			case "N":
				if (string.substr(j, 2).match(/\d\d/)) {
					minutes = int(string.substr(j, 2));
					if (minutes <= 59) {
						j += 2;
						break;
					}
				}
				minutes = int(string.substr(j, 1));
				j++;
				break;
			case "SS":
				seconds = int(string.substr(j, 2));
				j += 2;
				break;
			case "S":
				if (string.substr(j, 2).match(/\d\d/)) {
					seconds = int(string.substr(j, 2));
					if (seconds <= 59) {
						j += 2;
						break;
					}
				}
				seconds = int(string.substr(j, 1));
				j++;
				break;
			}
		}
		
		//patternがいずれかのパターンであるかどうか
		function isPattern(pattern:String):Boolean {
			switch (pattern) {
			case "YYYY":
			case "YY":
			case "MM":
			case "M":
			case "DD":
			case "D":
			case "HH":
			case "H":
			case "NN":
			case "N":
			case "SS":
			case "S":
				return true;
			}
			return false;
		}
		
		//patternがいずれかのパターンと前方一致するかどうか
		function isHeadOfPattern(pattern:String):Boolean {
			if (isPattern(pattern)) {
				return true;
			}
			switch (pattern) {
			case "YYY":
			case "Y":
			case "":
				return true;
			}
			return false;
		}
	}
	
}