TOOL-Converting JSON DateTime String to .NET DateTime Structure
| | | 0 | |
[Abstract] Sample code for converting "\/Date(1270051200000)\/" JSON format to .NET DateTime structure, it is used to convert log files with JSON-serialized data to make the date information readable.
專案裡有個Log機制會以JSON格式保存呼叫歷程中的參數物件,以便事後偵錯及追蹤之用。不過有個小困擾: 由於該Log模組採用JavaScriptSerializer進行序列化,DateTime型別會被格式化成"\/Date(1270051200000)\/"這種微軟獨創的日期表示格式(相關細節可參考舊文),在使用肉眼查看Log檔時,很難將其還原回時間,增加偵錯的難度。
我的構想是寫一個命令列轉檔程式,讀入Log檔並使用Regular Expression找出其中出現的"\/Date(1270051200000)\/"格式,將其置換成"2010/04/01T00:00:00Z"字串後輸出或另存檔案,用轉換後的檔案進行分析,即可避免JSON日期難以閱讀的問題。
在Javascript中,可輕易透過new Date(1270051200000)將"\/Date(1270051200000)\/"轉換成日期,在.NET內將其還原回DateTime時,則有一點小訣竅: Javascript中的tick是由1970/01/01 00:00:00起算的微秒(ms)數,而.NET的Ticks則是從0000/01/01 00:00:00起累計的100奈秒數(10ns, 等於千萬分之一秒),因此要經過轉換(乘上10,000再加上 621355968000000000, 1970/01/01 00:00:00的Ticks)才能算出正確時間。
以下是程式範例: (若要處理的檔案很大,用StringBuilder串接再一次寫入的做法會消耗大量記憶體,可考量改用StreamWriter讀一行寫一行的Streaming做法)
using System; using System.Text.RegularExpressions; using System.IO; using System.Text; namespace Darkthread { class Program { //getTime() in Javascript is milliseconds since January 1, 1970 //Ticks in .NET is nanoseconds since January 1, 0000 //new DateTime(1970, 1, 1).Ticks = 621355968000000000 static long baseTicks = 621355968000000000;
//Convert Javascript ticks to DateTime static string GetDateTimeString(long jsTicks, int utcDiff = 0)
{ return new DateTime(jsTicks * 10000 + baseTicks).AddHours(utcDiff)
.ToString("yyyy/MM/ddTHH:mm:ssZ"); }
//Convert JSON date string to DateTime static string GetDateTimeString(string jsonDateString)
{ int p = jsonDateString.IndexOf("(") + 1;
string numStr = jsonDateString.Substring(p, jsonDateString.IndexOf(")") - p );
int utcDiff = 0; string[] a = numStr.Split('+', '-');
if (a.Length == 2) { utcDiff = (numStr.Contains("-") ? -1 : 1) * int.Parse(a[1].Substring(0, 2)); numStr = a[0];
}
return GetDateTimeString(long.Parse(numStr), utcDiff);
}
static void Main(string[] args)
{ if (args.Length < 1 || args.Length > 2) { Console.WriteLine("Syntax: ConvJsonDate file_name or " + "ConvJsonDate file_name_*.ext output_path"); return; }
string fn = args[0]; string[] files = new string[] { fn };
//for wildcard search if (fn.Contains("*"))
{ string srcFolder = Path.GetDirectoryName(fn); //if no path assigned, use current folder if (string.IsNullOrEmpty(srcFolder))
srcFolder = "."; string pattern = Path.GetFileName(fn); files = Directory.GetFiles(srcFolder, pattern);
}
//get output path if assigned string path = args.Length > 1 ? args[1] : null;
//define regular expression pattern Regex re = new Regex(@"\\/Date\([0-9+-]+\)\\/");
StringBuilder sb = new StringBuilder(); foreach (string f in files)
{ using (StreamReader sr = new StreamReader(f))
{ string line; sb.Length = 0;
while ((line = sr.ReadLine()) != null)
//convert \/Date(....)\/ to yyyy-MM-ddTHH:mm:ssZ sb.AppendLine(
re.Replace(line, (o) => GetDateTimeString(o.Value)));
if (string.IsNullOrEmpty(path))
//if no path assigned, output the converted text to console Console.Write(sb.ToString());
else //if path is assigned, dump the converted text to files try { File.WriteAllText(Path.Combine(path, Path.GetFileName(f)),
sb.ToString());
}
catch (Exception ex) { Console.WriteLine(ex.Message);
return; }
}
}
}
}
}
將程式編譯成JConvJsonDate.exe後,有以幾種應用方式:
- ConvJsonDate.exe boo.log
進行JSON日期轉換後顯示檔案內容 - ConvJsonDate.exe boo.log > foo.log
對boo.log進行JSON日期轉換後將結果存為foo.log - ConvJsonDate.exe x:\logs\*.log d:\ConvLogs
對x:\logs目錄下的所有*.log進行轉換,並將轉換結果以同樣檔名寫入d:\ConvLogs
Comments
Be the first to post a comment