当前位置:  开发笔记 > 编程语言 > 正文

给定DateTime对象,如何以字符串格式获取ISO 8601日期?

如何解决《给定DateTime对象,如何以字符串格式获取ISO8601日期?》经验,为你挑选了14个好方法。

鉴于:

DateTime.UtcNow

如何获得符合ISO 8601格式的相同值的字符串?

请注意,ISO 8601定义了许多类似的格式.我正在寻找的具体格式是:

yyyy-MM-ddTHH:mm:ssZ

Wayne.. 739

DateTime.UtcNow.ToString("yyyy-MM-ddTHH\\:mm\\:ss.fffffffzzz");

这会给你一个类似于2008-09-22T13:57:31.2311892-04:00的日期.

另一种方式是:

DateTime.UtcNow.ToString("o");

哪个给你2008-09-22T14:01:54.9571247Z

要获取指定的格式,您可以使用:

DateTime.UtcNow.ToString("yyyy-MM-ddTHH:mm:ssZ")

日期时间格式选项



1> Wayne..:
DateTime.UtcNow.ToString("yyyy-MM-ddTHH\\:mm\\:ss.fffffffzzz");

这会给你一个类似于2008-09-22T13:57:31.2311892-04:00的日期.

另一种方式是:

DateTime.UtcNow.ToString("o");

哪个给你2008-09-22T14:01:54.9571247Z

要获取指定的格式,您可以使用:

DateTime.UtcNow.ToString("yyyy-MM-ddTHH:mm:ssZ")

日期时间格式选项


这些天,这样做(尝试使用偏移渲染UTC时间,这没有多大意义)会引发异常.所以,我同意其他人的观点,即具有不变文化的"s"格式可能更为正确.FYI,formatexception的消息是:"UTC日期时间正在转换为仅适用于本地时间的格式的文本.当使用'z'格式说明符调用DateTime.ToString时会发生这种情况,这将包括本地时区偏移量在输出中."
我住在澳大利亚,对我来说,我必须使用`ToString("yyyy-MM-ddTHH:mm:ssK")`才能使用(使用我使用的jquery timeago插件).
如果要包含时区偏移量,请执行以下操作:`dt.ToString("s")+ dt.ToString("zzz")`// 2013-12-05T07:19:04-08:00
@core:这是标准格式之一,它与链接的自定义格式不同:https://msdn.microsoft.com/en-us/library/az4se3k1(v = vs.110).aspx
斜杠(\ :)导致字符串问题...放入@字符以使用字符串文字.
如果您正在使用Windows Live REST服务,则还需要ToString("yyyy-MM-ddTHH:mm:ssK",System.Globalization.CultureInfo.InvariantCulture).

2> Simon Wilson..:

DateTime.UtcNow.ToString("s", System.Globalization.CultureInfo.InvariantCulture)应该给你你想要的东西,因为"s"格式说明符被描述为一个可排序的日期/时间模式; 符合ISO 8601.


我相信这是正确的答案.如果微软已经实现了ISO 8601,那么明确定义yyyy-MM-etc没有意义.Iain的反应也是正确的,但你应该总是指定InvariantCulture(或任何其他CultureInfo)有多种原因(即从不假设.NET应该只是假设).您还可以使用:`DateTime.UtcNow.ToString(CultureInfo.InvariantCulture.DateTimeFormat.SortableDateTimePattern);`但是,由于所有这些都排除了时区等,您可能别无选择,只能使用显式格式化程序,即` "YYYY-MM-DDTHH:MM:ss.fffZ"`
@ stimpy77为`"s"指定CultureInfo是没有意义的,因为:[""O"(或"o"),"R"(或"r"),"s"和"u".这些字符串对应于由不变文化定义的自定义格式字符串.它们生成日期和时间值的字符串表示,这些值在各种文化中都是相同的."](http://msdn.microsoft.com/en-us/library/system.globalization.datetimeformatinfo%28v=vs.110%29 )
虽然它符合,但它省略了时区,`Z`,看起来像这样:`DateTime.UtcNow.ToString(c,CultureInfo.InvariantCulture))=> 2012-06-26T11:55:36`并且没有毫秒分辨率非常好,因为计算机每秒钟会有相当数量的滴答声.
使用`o`,你得到`2012-06-26T11:55:36.1007668Z`意思是'36.1007668`秒,所以你得到的分辨率下降到1/10 ^ 7秒.来自ISO8601:2004`如果包含小数部分,则应省略低阶时间元素(如果有的话),小数部分应从整数部分除以逗号(,)或满的十进制符号[...]停止(.)`
@binki - 现在我很困惑.根据我之前为SortableDateTimePattern链接的文档(http://msdn.microsoft.com/en-us/library/system.globalization.datetimeformatinfo.sortabledatetimepattern(v = vs.110)),它说应该是文化具体.但是,它似乎与它自己的例子相矛盾(因为它们看起来都一样); 尝试`DateTime.Now.ToString("s",new CultureInfo(myCulture))`.
是的,"s"是令人困惑的.定义与实施?"**SortableDateTimePattern属性定义日期字符串**"的特定于文化的格式,但它是作为定义的标准实现的,不会改变每种文化:"SortableDateTimePattern属性返回的格式字符串反映**定义的标准( ISO 8601)**[...]因此,无论文化**如何,**总是相同的." 报价来自文档,https://msdn.microsoft.com/en-us/library/system.globalization.datetimeformatinfo.sortabledatetimepattern.aspx.

3> Iain..:
DateTime.UtcNow.ToString("s")

返回类似2008-04-10T06:30:00的内容

UtcNow显然会返回UTC时间,所以在以下方面没有任何危害:

string.Concat(DateTime.UtcNow.ToString("s"), "Z")


@KoenZomers:我不认为这是正确的.我认为`a + b`编译成与`string.Concat(a,b)`相同的中间代码(假设a和b当然是字符串),因此性能或内存消耗没有差别.
是的,马克是对的.Koen,即使你是对的,你刚刚陷入了荒谬的过早微优化的陷阱.
只是出于兴趣:为什么string.Concat()而不是'+'?
@ greg84:嗯,你并不完全正确.请看微软架构师Rico Mariani撰写的这篇文章:http://blogs.msdn.com/b/ricom/archive/2003/12/15/43628.aspx - 他说a + b确实编译为concat +还有更多信息关于StringBuilder的正确用法.
肯定有区别.当使用+来连接字符串时,在内存中保留三个内存块来存储字符串:一个用于第一个,一个用于第二个,一个用于完整字符串.总是使用string.Concat和string.Format,因为这些是更多的内存防腐,只保留一块内存.
哈比特,有区别吗?
@MarkByers,这不正确.@Noldorin,如果在执行数千次的循环中调用它,或者如果它是在每个请求上运行此代码的Web应用程序,那么现在还为时过早.在我看来,`string.Concat`应该*总是*用于密集的字符串连接(通过密集,我的意思是由应用程序定期使用,而不是用户 - 我再次考虑网络).@KoenZomers`tring.Format`实际上是最慢的方法.请参阅此页面中间的基准:http://www.dotnetperls.com/string-concat

4> 小智..:

使用:

private void TimeFormats()
{
    DateTime localTime = DateTime.Now;
    DateTime utcTime = DateTime.UtcNow;
    DateTimeOffset localTimeAndOffset = new DateTimeOffset(localTime, TimeZoneInfo.Local.GetUtcOffset(localTime));

    //UTC
    string strUtcTime_o = utcTime.ToString("o");
    string strUtcTime_s = utcTime.ToString("s");
    string strUtcTime_custom = utcTime.ToString("yyyy-MM-ddTHH:mm:ssK");

    //Local
    string strLocalTimeAndOffset_o = localTimeAndOffset.ToString("o");
    string strLocalTimeAndOffset_s = localTimeAndOffset.ToString("s");
    string strLocalTimeAndOffset_custom = utcTime.ToString("yyyy-MM-ddTHH:mm:ssK");

    //Output
    Response.Write("
UTC
"); Response.Write("strUtcTime_o: " + strUtcTime_o + "
"); Response.Write("strUtcTime_s: " + strUtcTime_s + "
"); Response.Write("strUtcTime_custom: " + strUtcTime_custom + "
"); Response.Write("
Local Time
"); Response.Write("strLocalTimeAndOffset_o: " + strLocalTimeAndOffset_o + "
"); Response.Write("strLocalTimeAndOffset_s: " + strLocalTimeAndOffset_s + "
"); Response.Write("strLocalTimeAndOffset_custom: " + strLocalTimeAndOffset_custom + "
"); }

OUTPUT

UTC
    strUtcTime_o: 2012-09-17T22:02:51.4021600Z
    strUtcTime_s: 2012-09-17T22:02:51
    strUtcTime_custom: 2012-09-17T22:02:51Z

Local Time
    strLocalTimeAndOffset_o: 2012-09-17T15:02:51.4021600-07:00
    strLocalTimeAndOffset_s: 2012-09-17T15:02:51
    strLocalTimeAndOffset_custom: 2012-09-17T22:02:51Z

资料来源:

标准日期和时间格式字符串(MSDN)

自定义日期和时间格式字符串(MSDN)


似乎你是在本地自定义复制的受害者;-)`string strLocalTimeAndOffset_custom = localTimeAndOffset.ToString("yyyy-MM-ddTHH:mm:ssK");`将导致:`strLocalTimeAndOffset_custom:2012-09-17T22:02: 51-07:00`

5> Henrik..:
System.DateTime.UtcNow.ToString("o")

=>

val it : string = "2013-10-13T13:03:50.2950037Z"



6> 小智..:

您可以使用下一个代码获得"Z"(ISO 8601 UTC):

Dim tmpDate As DateTime = New DateTime(Now.Ticks, DateTimeKind.Utc)
Dim res as String = tmpDate.toString("o") '2009-06-15T13:45:30.0000000Z


原因如下:

ISO 8601有一些不同的格式:

DateTimeKind.Local

2009-06-15T13:45:30.0000000-07:00

DateTimeKind.Utc

2009-06-15T13:45:30.0000000Z

DateTimeKind.Unspecified

2009-06-15T13:45:30.0000000


.NET为我们提供了这些选项的枚举:

'2009-06-15T13:45:30.0000000-07:00
Dim strTmp1 As String = New DateTime(Now.Ticks, DateTimeKind.Local).ToString("o")

'2009-06-15T13:45:30.0000000Z
Dim strTmp2 As String = New DateTime(Now.Ticks, DateTimeKind.Utc).ToString("o")

'2009-06-15T13:45:30.0000000
Dim strTmp3 As String = New DateTime(Now.Ticks, DateTimeKind.Unspecified).ToString("o")

注意:如果将Visual Studio 2008"监视实用程序"应用于toString("o")部分,您可能会得到不同的结果,我不知道它是否是一个错误,但在这种情况下,使用String变量可以获得更好的结果如果你正在调试

来源:标准日期和时间格式字符串(MSDN)



7> Alex Nolasco..:

如果必须将DateTime用于ISO 8601,那么ToString("o")应该产生您要查找的内容.例如,

2015-07-06T12:08:27

但是,DateTime + TimeZone可能会出现其他问题,如.NET中的DateTime和DateTimeOffset博客中所述:良好实践和常见陷阱:

DateTime中有无数陷阱,旨在为您的代码提供错误:

1.- DateTimeKind.Unspecified的DateTime值是坏消息.

2.- DateTime在进行比较时不关心UTC/Local.

3.- DateTime值不知道标准格式字符串.

4.-使用DateTime解析具有UTC标记的字符串不保证UTC时间.


ISO8601用于一个strava.但请使用:StartTime.ToString("yyyy-MM-ddTHH:mm:ssZ")而不是ToString("o"),它增加毫秒等.
对我来说,"yyyy-MM-dd-THH:mm:ssZ"字面意思是在我的字符串末尾输出"Z"而不是时区标记,这不符合我的要求.ToString("o")实际上做了我需要的,更容易和更短.

8> Sumrak..:

我会用XmlConvert:

XmlConvert.ToString(DateTime.UtcNow, XmlDateTimeSerializationMode.RoundtripKind);

它会自动保留时区.



9> Justin Turne..:

大多数答案都有毫秒/微秒,ISO 8601显然不支持.正确的答案是:

System.DateTime.Now.ToString("yyyy-MM-ddTHH:mm:ssK");
// or
System.DateTime.Now.ToUniversalTime().ToString("yyyy-MM-ddTHH:mm:ssK");

参考文献:

ISO 8601规范

"K"说明符


在"时代"下阅读您自己的维基百科链接.它提到"十进制分数",意味着ISO 8601支持毫秒和微秒(但通信方可能会限制接受的小数位数).

10> PSM..:
DateTime.Now.ToString("yyyy-MM-dd'T'HH:mm:ss zzz");

DateTime.Now.ToString("O");

注意:根据您在最后进行的转换,您将使用第一行(最喜欢它)或第二行.

确保仅在本地时间应用格式,因为"zzz"是UTC转换的时区信息.

图片



11> Oppositional..:

要将DateTime.UtcNow转换为yyyy-MM-ddTHH:mm:ssZ的字符串表示形式,可以将DateTime结构的ToString()方法与自定义格式字符串一起使用.将自定义格式字符串与DateTime一起使用时,请务必记住您需要使用单引号转义分隔符.

以下将返回您想要的字符串表示:

DateTime.UtcNow.ToString("yyyy'-'MM'-'dd'T'HH':'mm':'ss'Z'", DateTimeFormatInfo.InvariantInfo)



12> rburte..:

惊讶的是没有人建议:

System.DateTime.UtcNow.ToString("u").Replace(' ','T')

该UniversalSortableDateTimePattern让你几乎所有的方式给你想要的东西(这更多的是一个RFC 3339表示)。


补充:我决定使用答案/sf/ask/17360801/中的基准来比较其性能。

tl:dr; 这是在昂贵的一端。

实现方式:

[Benchmark]
public string ReplaceU()
{
   var text = dateTime.ToUniversalTime().ToString("u").Replace(' ', 'T');
   return text;
}

结果:

// * Summary *

BenchmarkDotNet=v0.11.5, OS=Windows 10.0.19002
Intel Xeon CPU E3-1245 v3 3.40GHz, 1 CPU, 8 logical and 4 physical cores
.NET Core SDK=3.0.100
  [Host]     : .NET Core 3.0.0 (CoreCLR 4.700.19.46205, CoreFX 4.700.19.46214), 64bit RyuJIT
  DefaultJob : .NET Core 3.0.0 (CoreCLR 4.700.19.46205, CoreFX 4.700.19.46214), 64bit RyuJIT


|               Method |     Mean |     Error |    StdDev |
|--------------------- |---------:|----------:|----------:|
|           CustomDev1 | 562.4 ns | 11.135 ns | 10.936 ns |
|           CustomDev2 | 525.3 ns |  3.322 ns |  3.107 ns |
|     CustomDev2WithMS | 609.9 ns |  9.427 ns |  8.356 ns |
|              FormatO | 356.6 ns |  6.008 ns |  5.620 ns |
|              FormatS | 589.3 ns |  7.012 ns |  6.216 ns |
|       FormatS_Verify | 599.8 ns | 12.054 ns | 11.275 ns |
|        CustomFormatK | 549.3 ns |  4.911 ns |  4.594 ns |
| CustomFormatK_Verify | 539.9 ns |  2.917 ns |  2.436 ns |
|             ReplaceU | 615.5 ns | 12.313 ns | 11.517 ns |

// * Hints *
Outliers
  BenchmarkDateTimeFormat.CustomDev2WithMS: Default     -> 1 outlier  was  removed (668.16 ns)
  BenchmarkDateTimeFormat.FormatS: Default              -> 1 outlier  was  removed (621.28 ns)
  BenchmarkDateTimeFormat.CustomFormatK: Default        -> 1 outlier  was  detected (542.55 ns)
  BenchmarkDateTimeFormat.CustomFormatK_Verify: Default -> 2 outliers were removed (557.07 ns, 560.95 ns)

// * Legends *
  Mean   : Arithmetic mean of all measurements
  Error  : Half of 99.9% confidence interval
  StdDev : Standard deviation of all measurements
  1 ns   : 1 Nanosecond (0.000000001 sec)

// ***** BenchmarkRunner: End *****



13> 小智..:

"s"标准格式说明代表在由定义的自定义的日期和时间的格式字符串DateTimeFormatInfo.SortableDateTimePattern属性.该模式反映了已定义的标准(ISO 8601),并且该属性是只读的.因此,无论使用何种文化或提供格式提供程序,它始终是相同的.自定义格式字符串是"yyyy'-'MM'-'dd'T'HH':'mm':'ss".

使用此标准格式说明符时,格式化或解析操作始终使用不变文化.

- 来自MSDN



14> Roman Pokrov..:

有趣的是,自定义格式"yyyy-MM-ddTHH:mm:ssK"(没有ms)是最快的格式方法.

另外有趣的是,"S"格式在Classic上很慢而在Core上很快......

当然数字非常接近,某些行之间的差异无关紧要(带后缀的测试与没有后缀的测试_Verify相同,显示结果可重复性)

BenchmarkDotNet=v0.10.5, OS=Windows 10.0.14393
Processor=Intel Core i5-2500K CPU 3.30GHz (Sandy Bridge), ProcessorCount=4
Frequency=3233539 Hz, Resolution=309.2587 ns, Timer=TSC
  [Host] : Clr 4.0.30319.42000, 64bit RyuJIT-v4.6.1637.0
  Clr    : Clr 4.0.30319.42000, 64bit RyuJIT-v4.6.1637.0
  Core   : .NET Core 4.6.25009.03, 64bit RyuJIT


               Method |  Job | Runtime |       Mean |     Error |    StdDev |     Median |        Min |        Max | Rank |  Gen 0 | Allocated |
--------------------- |----- |-------- |-----------:|----------:|----------:|-----------:|-----------:|-----------:|-----:|-------:|----------:|
           CustomDev1 |  Clr |     Clr | 1,089.0 ns | 22.179 ns | 20.746 ns | 1,079.9 ns | 1,068.9 ns | 1,133.2 ns |    8 | 0.1086 |     424 B |
           CustomDev2 |  Clr |     Clr | 1,032.3 ns | 19.897 ns | 21.289 ns | 1,024.7 ns | 1,000.3 ns | 1,072.0 ns |    7 | 0.1165 |     424 B |
     CustomDev2WithMS |  Clr |     Clr | 1,168.2 ns | 16.543 ns | 15.474 ns | 1,168.5 ns | 1,149.3 ns | 1,189.2 ns |   10 | 0.1625 |     592 B |
              FormatO |  Clr |     Clr | 1,563.7 ns | 31.244 ns | 54.721 ns | 1,532.5 ns | 1,497.8 ns | 1,703.5 ns |   14 | 0.2897 |     976 B |
              FormatS |  Clr |     Clr | 1,243.5 ns | 24.615 ns | 31.130 ns | 1,229.3 ns | 1,200.6 ns | 1,324.2 ns |   13 | 0.2865 |     984 B |
       FormatS_Verify |  Clr |     Clr | 1,217.6 ns | 11.486 ns | 10.744 ns | 1,216.2 ns | 1,205.5 ns | 1,244.3 ns |   12 | 0.2885 |     984 B |
        CustomFormatK |  Clr |     Clr |   912.2 ns | 17.915 ns | 18.398 ns |   916.6 ns |   878.3 ns |   934.1 ns |    4 | 0.0629 |     240 B |
 CustomFormatK_Verify |  Clr |     Clr |   894.0 ns |  3.877 ns |  3.626 ns |   893.8 ns |   885.1 ns |   900.0 ns |    3 | 0.0636 |     240 B |
           CustomDev1 | Core |    Core |   989.1 ns | 12.550 ns | 11.739 ns |   983.8 ns |   976.8 ns | 1,015.5 ns |    6 | 0.1101 |     423 B |
           CustomDev2 | Core |    Core |   964.3 ns | 18.826 ns | 23.809 ns |   954.1 ns |   935.5 ns | 1,015.6 ns |    5 | 0.1267 |     423 B |
     CustomDev2WithMS | Core |    Core | 1,136.0 ns | 21.914 ns | 27.714 ns | 1,138.1 ns | 1,099.9 ns | 1,200.2 ns |    9 | 0.1752 |     590 B |
              FormatO | Core |    Core | 1,201.5 ns | 16.262 ns | 15.211 ns | 1,202.3 ns | 1,178.2 ns | 1,225.5 ns |   11 | 0.0656 |     271 B |
              FormatS | Core |    Core |   993.5 ns | 19.272 ns | 24.372 ns |   999.4 ns |   954.2 ns | 1,029.5 ns |    6 | 0.0633 |     279 B |
       FormatS_Verify | Core |    Core | 1,003.1 ns | 17.577 ns | 16.442 ns | 1,009.2 ns |   976.1 ns | 1,024.3 ns |    6 | 0.0674 |     279 B |
        CustomFormatK | Core |    Core |   878.2 ns | 17.017 ns | 20.898 ns |   877.7 ns |   851.4 ns |   928.1 ns |    2 | 0.0555 |     215 B |
 CustomFormatK_Verify | Core |    Core |   863.6 ns |  3.968 ns |  3.712 ns |   863.0 ns |   858.6 ns |   870.8 ns |    1 | 0.0550 |     215 B |

码:

    public class BenchmarkDateTimeFormat
    {
        public static DateTime dateTime = DateTime.Now;

        [Benchmark]
        public string CustomDev1()
        {
            var d = dateTime.ToUniversalTime();
            var sb = new StringBuilder(20);

            sb.Append(d.Year).Append("-");
            if (d.Month <= 9)
                sb.Append("0");
            sb.Append(d.Month).Append("-");
            if (d.Day <= 9)
                sb.Append("0");
            sb.Append(d.Day).Append("T");
            if (d.Hour <= 9)
                sb.Append("0");
            sb.Append(d.Hour).Append(":");
            if (d.Minute <= 9)
                sb.Append("0");
            sb.Append(d.Minute).Append(":");
            if (d.Second <= 9)
                sb.Append("0");
            sb.Append(d.Second).Append("Z");
            var text = sb.ToString();
            return text;
        }

        [Benchmark]
        public string CustomDev2()
        {
            var u = dateTime.ToUniversalTime();
            var sb = new StringBuilder(20);
            var y = u.Year;
            var d = u.Day;
            var M = u.Month;
            var h = u.Hour;
            var m = u.Minute;
            var s = u.Second;
            sb.Append(y).Append("-");
            if (M <= 9)
                sb.Append("0");
            sb.Append(M).Append("-");
            if (d <= 9)
                sb.Append("0");
            sb.Append(d).Append("T");
            if (h <= 9)
                sb.Append("0");
            sb.Append(h).Append(":");
            if (m <= 9)
                sb.Append("0");
            sb.Append(m).Append(":");
            if (s <= 9)
                sb.Append("0");
            sb.Append(s).Append("Z");
            var text = sb.ToString();
            return text;
        }

        [Benchmark]
        public string CustomDev2WithMS()
        {
            var u  = dateTime.ToUniversalTime();
            var sb = new StringBuilder(23);
            var y  = u.Year;
            var d  = u.Day;
            var M  = u.Month;
            var h  = u.Hour;
            var m  = u.Minute;
            var s  = u.Second;
            var ms = u.Millisecond;
            sb.Append(y).Append("-");
            if (M <= 9)
                sb.Append("0");
            sb.Append(M).Append("-");
            if (d <= 9)
                sb.Append("0");
            sb.Append(d).Append("T");
            if (h <= 9)
                sb.Append("0");
            sb.Append(h).Append(":");
            if (m <= 9)
                sb.Append("0");
            sb.Append(m).Append(":");
            if (s <= 9)
                sb.Append("0");
            sb.Append(s).Append(".");
            sb.Append(ms).Append("Z");
            var text = sb.ToString();
            return text;
        }
        [Benchmark]
        public string FormatO()
        {
            var text = dateTime.ToUniversalTime().ToString("o");
            return text;
        }
        [Benchmark]
        public string FormatS()
        {
            var text = string.Concat(dateTime.ToUniversalTime().ToString("s"),"Z");
            return text;
        }

        [Benchmark]
        public string FormatS_Verify()
        {
            var text = string.Concat(dateTime.ToUniversalTime().ToString("s"), "Z");
            return text;
        }

        [Benchmark]
        public string CustomFormatK()
        {
            var text = dateTime.ToUniversalTime().ToString("yyyy-MM-ddTHH:mm:ssK");
            return text;
        }

        [Benchmark]
        public string CustomFormatK_Verify()
        {
            var text = dateTime.ToUniversalTime().ToString("yyyy-MM-ddTHH:mm:ssK");
            return text;
        }
    }

https://github.com/dotnet/BenchmarkDotNet使用

推荐阅读
夏晶阳--艺术
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有