16
16
using System . Text ;
17
17
using ServiceStack . Text . Json ;
18
18
using ServiceStack . Text . Support ;
19
+ using System . Text . RegularExpressions ;
19
20
20
21
namespace ServiceStack . Text . Common
21
22
{
@@ -29,7 +30,9 @@ public static class DateTimeSerializer
29
30
public const string XsdDateTimeFormat3F = "yyyy-MM-ddTHH:mm:ss.fffZ" ; //25
30
31
public const string XsdDateTimeFormatSeconds = "yyyy-MM-ddTHH:mm:ssZ" ; //21
31
32
public const string DateTimeFormatSecondsUtcOffset = "yyyy-MM-ddTHH:mm:sszzz" ; //22
33
+ public const string DateTimeFormatSecondsNoOffset = "yyyy-MM-ddTHH:mm:ss" ;
32
34
public const string DateTimeFormatTicksUtcOffset = "yyyy-MM-ddTHH:mm:ss.fffffffzzz" ; //30
35
+ public const string DateTimeFormatTicksNoUtcOffset = "yyyy-MM-ddTHH:mm:ss.fffffff" ;
33
36
34
37
public const string EscapedWcfJsonPrefix = "\\ /Date(" ;
35
38
public const string EscapedWcfJsonSuffix = ")\\ /" ;
@@ -42,7 +45,7 @@ public static class DateTimeSerializer
42
45
private static readonly int XsdTimeSeparatorIndex = XsdDateTimeFormat . IndexOf ( XsdTimeSeparator ) ;
43
46
private const string XsdUtcSuffix = "Z" ;
44
47
private static readonly char [ ] DateTimeSeperators = new [ ] { '-' , '/' } ;
45
-
48
+ private static readonly Regex UtcOffsetInfoRegex = new Regex ( "([+-](?:2[0-3]|[0-1][0-9]):[0-5][0-9])" , RegexOptions . Compiled ) ;
46
49
public static Func < string , Exception , DateTime > OnParseErrorFn { get ; set ; }
47
50
48
51
/// <summary>
@@ -52,14 +55,15 @@ public static class DateTimeSerializer
52
55
/// <returns></returns>
53
56
public static DateTime Prepare ( this DateTime dateTime , bool parsedAsUtc = false )
54
57
{
55
- if ( JsConfig . AlwaysUseUtc )
58
+ if ( JsConfig . SkipDateTimeConversion )
56
59
{
57
- return dateTime . Kind != DateTimeKind . Utc ? dateTime . ToStableUniversalTime ( ) : dateTime ;
60
+ return dateTime ;
58
61
}
59
- if ( JsConfig . PreserveUtc && dateTime . Kind == DateTimeKind . Utc )
62
+ if ( JsConfig . AlwaysUseUtc )
60
63
{
61
- return dateTime ;
64
+ return dateTime . Kind != DateTimeKind . Utc ? dateTime . ToStableUniversalTime ( ) : dateTime ;
62
65
}
66
+
63
67
return parsedAsUtc ? dateTime . ToLocalTime ( ) : dateTime ;
64
68
}
65
69
@@ -104,6 +108,7 @@ public static DateTime ParseShortestXsdDateTime(string dateTimeStr)
104
108
105
109
return unspecifiedDate . Prepare ( ) ;
106
110
}
111
+ DateTimeKind kind = DateTimeKind . Unspecified ;
107
112
108
113
switch ( JsConfig . DateHandler )
109
114
{
@@ -117,6 +122,12 @@ public static DateTime ParseShortestXsdDateTime(string dateTimeStr)
117
122
if ( long . TryParse ( dateTimeStr , out unixTimeMs ) )
118
123
return unixTimeMs . FromUnixTimeMs ( ) ;
119
124
break ;
125
+ case DateHandler . ISO8601 :
126
+ if ( JsConfig . SkipDateTimeConversion )
127
+ {
128
+ dateTimeStr = RemoveUtcOffsets ( dateTimeStr , out kind ) ;
129
+ }
130
+ break ;
120
131
}
121
132
122
133
dateTimeStr = RepairXsdTimeSeparator ( dateTimeStr ) ;
@@ -153,7 +164,20 @@ public static DateTime ParseShortestXsdDateTime(string dateTimeStr)
153
164
154
165
try
155
166
{
156
- var dateTime = DateTime . Parse ( dateTimeStr , null , DateTimeStyles . AssumeLocal ) ;
167
+ DateTime dateTime ;
168
+ if ( JsConfig . SkipDateTimeConversion )
169
+ {
170
+ dateTime = DateTime . Parse ( dateTimeStr , null ,
171
+ kind == DateTimeKind . Unspecified ?
172
+ DateTimeStyles . None :
173
+ kind == DateTimeKind . Local ?
174
+ DateTimeStyles . AssumeLocal :
175
+ DateTimeStyles . AssumeUniversal ) ;
176
+ }
177
+ else
178
+ {
179
+ dateTime = DateTime . Parse ( dateTimeStr , null , DateTimeStyles . AssumeLocal ) ;
180
+ }
157
181
return dateTime . Prepare ( ) ;
158
182
}
159
183
catch ( FormatException )
@@ -174,6 +198,18 @@ public static DateTime ParseShortestXsdDateTime(string dateTimeStr)
174
198
}
175
199
}
176
200
201
+ private static string RemoveUtcOffsets ( string dateTimeStr , out DateTimeKind kind )
202
+ {
203
+ var startOfTz = UtcOffsetInfoRegex . Match ( dateTimeStr ) ;
204
+ if ( startOfTz . Index > 0 )
205
+ {
206
+ kind = DateTimeKind . Local ;
207
+ return dateTimeStr . Substring ( 0 , startOfTz . Index ) ;
208
+ }
209
+ kind = dateTimeStr . Contains ( "Z" ) ? DateTimeKind . Utc : DateTimeKind . Unspecified ;
210
+ return dateTimeStr ;
211
+ }
212
+
177
213
/// <summary>
178
214
/// Repairs an out-of-spec XML date/time string which incorrectly uses a space instead of a 'T' to separate the date from the time.
179
215
/// These string are occasionally generated by SQLite and can cause errors in OrmLite when reading these columns from the DB.
@@ -213,7 +249,7 @@ private static string RepairXsdTimeSeparator(string dateTimeStr)
213
249
if ( dateTimeStr . EndsWith ( XsdUtcSuffix ) )
214
250
{
215
251
dateTimeStr = dateTimeStr . Substring ( 0 , dateTimeStr . Length - 1 ) ;
216
- dateKind = JsConfig . PreserveUtc ? DateTimeKind . Utc : dateKind ;
252
+ dateKind = JsConfig . SkipDateTimeConversion ? DateTimeKind . Utc : dateKind ;
217
253
}
218
254
219
255
var parts = dateTimeStr . Split ( 'T' ) ;
@@ -412,19 +448,37 @@ public static string ToShortestXsdDateTimeString(DateTime dateTime)
412
448
var timeOfDay = dateTime . TimeOfDay ;
413
449
414
450
var isStartOfDay = timeOfDay . Ticks == 0 ;
415
- if ( isStartOfDay && ! ( JsConfig . PreserveUtc && dateTime . Kind == DateTimeKind . Utc ) )
451
+ if ( isStartOfDay && ! ( JsConfig . SkipDateTimeConversion ) )
416
452
return dateTime . ToString ( ShortDateTimeFormat ) ;
417
453
418
454
var hasFractionalSecs = ( timeOfDay . Milliseconds != 0 )
419
455
|| ( ( timeOfDay . Ticks % TimeSpan . TicksPerMillisecond ) != 0 ) ;
420
- if ( ! hasFractionalSecs )
421
- return dateTime . Kind != DateTimeKind . Utc
422
- ? dateTime . ToString ( DateTimeFormatSecondsUtcOffset )
423
- : dateTime . ToStableUniversalTime ( ) . ToString ( XsdDateTimeFormatSeconds ) ;
456
+ if ( JsConfig . SkipDateTimeConversion )
457
+ {
458
+ if ( ! hasFractionalSecs )
459
+ return dateTime . Kind == DateTimeKind . Local
460
+ ? dateTime . ToString ( DateTimeFormatSecondsUtcOffset )
461
+ : dateTime . Kind == DateTimeKind . Unspecified
462
+ ? dateTime . ToString ( DateTimeFormatSecondsNoOffset )
463
+ : dateTime . ToStableUniversalTime ( ) . ToString ( XsdDateTimeFormatSeconds ) ;
464
+
465
+ return dateTime . Kind == DateTimeKind . Local
466
+ ? dateTime . ToString ( DateTimeFormatTicksUtcOffset )
467
+ : dateTime . Kind == DateTimeKind . Unspecified
468
+ ? dateTime . ToString ( DateTimeFormatTicksNoUtcOffset )
469
+ : PclExport . Instance . ToXsdDateTimeString ( dateTime ) ;
470
+ }
471
+ else
472
+ {
473
+ if ( ! hasFractionalSecs )
474
+ return dateTime . Kind != DateTimeKind . Utc
475
+ ? dateTime . ToString ( DateTimeFormatSecondsUtcOffset )
476
+ : dateTime . ToStableUniversalTime ( ) . ToString ( XsdDateTimeFormatSeconds ) ;
424
477
425
- return dateTime . Kind != DateTimeKind . Utc
426
- ? dateTime . ToString ( DateTimeFormatTicksUtcOffset )
427
- : PclExport . Instance . ToXsdDateTimeString ( dateTime ) ;
478
+ return dateTime . Kind != DateTimeKind . Utc
479
+ ? dateTime . ToString ( DateTimeFormatTicksUtcOffset )
480
+ : PclExport . Instance . ToXsdDateTimeString ( dateTime ) ;
481
+ }
428
482
}
429
483
430
484
static readonly char [ ] TimeZoneChars = new [ ] { '+' , '-' } ;
@@ -541,7 +595,15 @@ public static void WriteWcfJsonDate(TextWriter writer, DateTime dateTime)
541
595
542
596
if ( JsConfig . DateHandler == DateHandler . ISO8601 )
543
597
{
544
- writer . Write ( dateTime . ToString ( "o" , CultureInfo . InvariantCulture ) ) ;
598
+ if ( ! JsConfig . SkipDateTimeConversion )
599
+ {
600
+ writer . Write ( dateTime . ToString ( "o" , CultureInfo . InvariantCulture ) ) ;
601
+ }
602
+ else
603
+ {
604
+ var dt = dateTime . ToString ( "o" , CultureInfo . InvariantCulture ) ;
605
+ writer . Write ( dt ) ;
606
+ }
545
607
return ;
546
608
}
547
609
0 commit comments