Skip to content

Commit 265a274

Browse files
authored
Use ToUnixTimeMilliseconds (#46036)
1 parent 93de54c commit 265a274

25 files changed

+171
-102
lines changed

docs/standard/datetime/system-text-json-support.md

Lines changed: 27 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ The `System.Text.Json` library parses and writes <xref:System.DateTime> and <xre
2222

2323
The <xref:System.Text.Json.JsonSerializer>, <xref:System.Text.Json.Utf8JsonReader>, <xref:System.Text.Json.Utf8JsonWriter>,
2424
and <xref:System.Text.Json.JsonElement> types parse and write <xref:System.DateTime> and <xref:System.DateTimeOffset>
25-
text representations according to the extended profile of the ISO 8601-1:2019 format. For example, `2019-07-26T16:59:57-05:00`.
25+
text representations according to the extended profile of the ISO 8601-1:2019 format, for example, `2019-07-26T16:59:57-05:00`.
2626

2727
<xref:System.DateTime> and <xref:System.DateTimeOffset> data can be serialized with <xref:System.Text.Json.JsonSerializer>:
2828

@@ -32,18 +32,16 @@ text representations according to the extended profile of the ISO 8601-1:2019 fo
3232

3333
:::code language="csharp" source="snippets/system-text-json-support/csharp/deserializing-with-jsonserializer-valid/Program.cs":::
3434

35-
With default options, input <xref:System.DateTime> and <xref:System.DateTimeOffset> text representations must conform to the extended ISO 8601-1:2019 profile.
36-
Attempting to deserialize representations that don't conform to the profile will cause <xref:System.Text.Json.JsonSerializer> to throw a <xref:System.Text.Json.JsonException>:
35+
With default options, input <xref:System.DateTime> and <xref:System.DateTimeOffset> text representations must conform to the extended ISO 8601-1:2019 profile. If you attempt to deserialize representations that don't conform to the profile, <xref:System.Text.Json.JsonSerializer> throws a <xref:System.Text.Json.JsonException>:
3736

3837
:::code language="csharp" source="snippets/system-text-json-support/csharp/deserializing-with-jsonserializer-error/Program.cs":::
3938

40-
The <xref:System.Text.Json.JsonDocument> provides structured access to the contents of a JSON payload, including <xref:System.DateTime>
41-
and <xref:System.DateTimeOffset> representations. The following example shows how to calculate the average
39+
<xref:System.Text.Json.JsonDocument> provides structured access to the contents of a JSON payload, including <xref:System.DateTime> and <xref:System.DateTimeOffset> representations. The following example shows how to calculate the average
4240
temperature on Mondays from a collection of temperatures:
4341

4442
:::code language="csharp" source="snippets/system-text-json-support/csharp/computing-with-jsondocument-valid/Program.cs":::
4543

46-
Attempting to compute the average temperature given a payload with non-compliant <xref:System.DateTime> representations will cause <xref:System.Text.Json.JsonDocument> to throw a <xref:System.FormatException>:
44+
If you attempt to compute the average temperature given a payload with non-compliant <xref:System.DateTime> representations, <xref:System.Text.Json.JsonDocument> throws a <xref:System.FormatException>:
4745

4846
:::code language="csharp" source="snippets/system-text-json-support/csharp/computing-with-jsondocument-error/Program.cs":::
4947

@@ -55,7 +53,7 @@ The lower level <xref:System.Text.Json.Utf8JsonWriter> writes <xref:System.DateT
5553

5654
:::code language="csharp" source="snippets/system-text-json-support/csharp/reading-with-utf8jsonreader-valid/Program.cs":::
5755

58-
Attempting to read non-compliant formats with <xref:System.Text.Json.Utf8JsonReader> will cause it to throw a <xref:System.FormatException>:
56+
If you attempt to read non-compliant formats with <xref:System.Text.Json.Utf8JsonReader>, it throws a <xref:System.FormatException>:
5957

6058
:::code language="csharp" source="snippets/system-text-json-support/csharp/reading-with-utf8jsonreader-error/Program.cs":::
6159

@@ -67,8 +65,12 @@ Attempting to read non-compliant formats with <xref:System.Text.Json.Utf8JsonRea
6765

6866
### When using <xref:System.Text.Json.JsonSerializer>
6967

70-
If you want the serializer to perform custom parsing or formatting, you can implement [custom converters](xref:System.Text.Json.Serialization.JsonConverter%601).
71-
Here are a few examples:
68+
If you want the serializer to perform custom parsing or formatting, you can implement [custom converters](xref:System.Text.Json.Serialization.JsonConverter%601). The following sections show a few examples:
69+
70+
- [DateTime(Offset).Parse and DateTime(Offset).ToString](#datetimeoffsetparse-and-datetimeoffsettostring)
71+
- [Utf8Parser and Utf8Formatter](#-and-)
72+
- [Use DateTime(Offset).Parse as a fallback](#use-datetimeoffsetparse-as-a-fallback)
73+
- [Use Unix epoch date format](#use-unix-epoch-date-format)
7274

7375
#### DateTime(Offset).Parse and DateTime(Offset).ToString
7476

@@ -135,7 +137,7 @@ and then written with the <xref:System.Text.Json.Utf8JsonWriter.WriteStringValue
135137
### When using <xref:System.Text.Json.Utf8JsonReader>
136138

137139
If you want to read a custom <xref:System.DateTime> or <xref:System.DateTimeOffset> text representation with <xref:System.Text.Json.Utf8JsonReader>,
138-
you can get the value of the current JSON token as a <xref:System.String> using <xref:System.Text.Json.Utf8JsonReader.GetString> method, then parse the value using custom logic.
140+
you can get the value of the current JSON token as a <xref:System.String> using the <xref:System.Text.Json.Utf8JsonReader.GetString> method, then parse the value using custom logic.
139141

140142
The following example shows how a custom <xref:System.DateTimeOffset> text representation can be retrieved using the <xref:System.Text.Json.Utf8JsonReader.GetString> method,
141143
then parsed using <xref:System.DateTimeOffset.ParseExact(System.String,System.String,System.IFormatProvider)>:
@@ -146,24 +148,23 @@ then parsed using <xref:System.DateTimeOffset.ParseExact(System.String,System.St
146148

147149
### Date and time components
148150

149-
The extended ISO 8601-1:2019 profile implemented in <xref:System.Text.Json?displayProperty=fullName> defines the following components for
150-
date and time representations. These components are used to define various supported levels of granularity
151+
The extended ISO 8601-1:2019 profile implemented in <xref:System.Text.Json?displayProperty=fullName> defines the following components for date and time representations. These components are used to define various supported levels of granularity
151152
when parsing and formatting <xref:System.DateTime> and <xref:System.DateTimeOffset> representations.
152153

153-
| Component | Format | Description |
154-
|-----------------|-----------------------------|---------------------------------------------------------------------------------|
155-
| Year | "yyyy" | 0001-9999 |
156-
| Month | "MM" | 01-12 |
157-
| Day | "dd" | 01-28, 01-29, 01-30, 01-31 based on month/year. |
158-
| Hour | "HH" | 00-23 |
159-
| Minute | "mm" | 00-59 |
160-
| Second | "ss" | 00-59 |
161-
| Second fraction | "FFFFFFF" | Minimum of one digit, maximum of 16 digits. |
162-
| Time offset | "K" | Either "Z" or "('+'/'-')HH':'mm". |
163-
| Partial time | "HH':'mm':'ss[FFFFFFF]" | Time without UTC offset information. |
164-
| Full date | "yyyy'-'MM'-'dd" | Calendar date. |
165-
| Full time | "'Partial time'K" | UTC of day or Local time of day with the time offset between local time and UTC.|
166-
| Date time | "'Full date''T''Full time'" | Calendar date and time of day, for example, 2019-07-26T16:59:57-05:00. |
154+
| Component | Format | Description |
155+
|-----------------|-------------------------|-------------------------------------------------|
156+
| Year | "yyyy" | 0001-9999 |
157+
| Month | "MM" | 01-12 |
158+
| Day | "dd" | 01-28, 01-29, 01-30, 01-31 based on month/year. |
159+
| Hour | "HH" | 00-23 |
160+
| Minute | "mm" | 00-59 |
161+
| Second | "ss" | 00-59 |
162+
| Second fraction | "FFFFFFF" | Minimum of one digit, maximum of 16 digits. |
163+
| Time offset | "K" | Either "Z" or "('+'/'-')HH':'mm". |
164+
| Partial time | "HH':'mm':'ss[FFFFFFF]" | Time without UTC offset information. |
165+
| Full date | "yyyy'-'MM'-'dd" | Calendar date. |
166+
| Full time | "'Partial time'K" | UTC of day or Local time of day with the time offset between local time and UTC.|
167+
| Date time | "'Full date''T''Full time'" | Calendar date and time of day, for example, 2019-07-26T16:59:57-05:00. |
167168

168169
### Support for parsing
169170

docs/standard/serialization/system-text-json/migrate-from-newtonsoft.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -23,8 +23,8 @@ The `System.Text.Json` namespace provides functionality for serializing to and d
2323
* .NET Framework 4.6.2 and later versions
2424
* .NET Core 2.0, 2.1, and 2.2
2525

26-
>[!TIP]
27-
> You can use AI assistance to [migrate from `Newtonsoft.Json` with GitHub Copilot](#use-github-copilot-to-migrate).
26+
> [!TIP]
27+
> You can use AI assistance to [migrate from `Newtonsoft.Json`](#use-github-copilot-to-migrate).
2828
2929
`System.Text.Json` focuses primarily on performance, security, and standards compliance. It has some key differences in default behavior and doesn't aim to have feature parity with `Newtonsoft.Json`. For some scenarios, `System.Text.Json` currently has no built-in functionality, but there are recommended workarounds. For other scenarios, workarounds are impractical.
3030

@@ -380,7 +380,7 @@ Starting in .NET 7, you can use the C# `required` modifier or the <xref:System.T
380380
* The `DateTimeZoneHandling` setting can be used to serialize all `DateTime` values as UTC dates.
381381
* The `DateFormatString` setting and `DateTime` converters can be used to customize the format of date strings.
382382

383-
<xref:System.Text.Json?displayProperty=fullName> supports ISO 8601-1:2019, including the RFC 3339 profile. This format is widely adopted, unambiguous, and makes round trips precisely. To use any other format, create a custom converter. For example, the following converters serialize and deserialize JSON that uses Unix epoch format with or without a time zone offset (values such as `/Date(1590863400000-0700)/` or `/Date(1590863400000)/`):
383+
<xref:System.Text.Json> supports ISO 8601-1:2019, including the RFC 3339 profile. This format is widely adopted, unambiguous, and makes round trips precisely. To use any other format, create a custom converter. For example, the following converters serialize and deserialize JSON that uses Unix epoch format with or without a time zone offset (values such as `/Date(1590863400000-0700)/` or `/Date(1590863400000)/`):
384384

385385
:::code language="csharp" source="snippets/how-to-contd/csharp/CustomConverterUnixEpochDate.cs" id="ConverterOnly":::
386386

docs/standard/serialization/system-text-json/snippets/how-to-contd/csharp/CopyOptions.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ public class Forecast
1111

1212
public class Program
1313
{
14-
public static void Main()
14+
public static void Run()
1515
{
1616
Forecast forecast = new()
1717
{

docs/standard/serialization/system-text-json/snippets/how-to-contd/csharp/CustomConverterHandleNull.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ public override void Write(
3131

3232
public class Program
3333
{
34-
public static void Main()
34+
public static void Run()
3535
{
3636
string json = @"{""x"":1,""y"":2,""Description"":null}";
3737

docs/standard/serialization/system-text-json/snippets/how-to-contd/csharp/CustomConverterInferredTypesToObject.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ public class WeatherForecast
3535

3636
public class Program
3737
{
38-
public static void Main()
38+
public static void Run()
3939
{
4040
string jsonString = """
4141
{

docs/standard/serialization/system-text-json/snippets/how-to-contd/csharp/CustomConverterPreserveReferences.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -101,7 +101,7 @@ class MyReferenceHandler : ReferenceHandler
101101

102102
public class Program
103103
{
104-
public static void Main()
104+
public static void Run()
105105
{
106106
Employee tyler = new()
107107
{

docs/standard/serialization/system-text-json/snippets/how-to-contd/csharp/CustomConverterUnixEpochDate.cs

Lines changed: 49 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -2,29 +2,50 @@
22
using System.Text.Json;
33
using System.Text.Json.Serialization;
44
using System.Text.RegularExpressions;
5+
using Newtonsoft.Json;
56

67
namespace CustomConverterUnixEpochDate
78
{
89
class Program
910
{
10-
public static void Main()
11+
public static void STJExample(DateTimeOffset date)
1112
{
1213
var forecast = new Forecast()
1314
{
14-
Date = DateTimeOffset.Now,
15+
Date = date,
1516
TemperatureCelsius = 19,
1617
Summary = "warm"
1718
};
1819

1920
var options = new JsonSerializerOptions();
2021
options.Converters.Add(new UnixEpochDateTimeOffsetConverter());
21-
options.WriteIndented = true;
2222

23-
string json = JsonSerializer.Serialize(forecast, options);
24-
Console.WriteLine(json);
23+
string json = System.Text.Json.JsonSerializer.Serialize(forecast, options);
24+
Console.WriteLine($"System.Text.Json: {json}");
2525

26-
Forecast forecastDeserialized = JsonSerializer.Deserialize<Forecast>(json, options)!;
27-
Console.WriteLine($"Deserialized date = {forecastDeserialized.Date}");
26+
Forecast forecastDeserialized = System.Text.Json.JsonSerializer.Deserialize<Forecast>(json, options)!;
27+
Console.WriteLine($"System.Text.Json deserialized date = {forecastDeserialized.Date}");
28+
}
29+
30+
public static void NewtonsoftExample(DateTimeOffset date)
31+
{
32+
var forecast = new Forecast()
33+
{
34+
Date = date,
35+
TemperatureCelsius = 19,
36+
Summary = "warm"
37+
};
38+
39+
var settings = new JsonSerializerSettings
40+
{
41+
DateFormatHandling = DateFormatHandling.MicrosoftDateFormat,
42+
};
43+
44+
string json = JsonConvert.SerializeObject(forecast, settings);
45+
Console.WriteLine($"{Environment.NewLine}Newtonsoft: {json}");
46+
47+
Forecast forecastDeserialized = JsonConvert.DeserializeObject<Forecast>(json, settings)!;
48+
Console.WriteLine($"Newtonsoft deserialized date = {forecastDeserialized.Date}");
2849
}
2950
}
3051

@@ -36,23 +57,28 @@ public class Forecast
3657
}
3758

3859
// <ConverterOnly>
39-
sealed class UnixEpochDateTimeOffsetConverter : JsonConverter<DateTimeOffset>
60+
sealed class UnixEpochDateTimeOffsetConverter : System.Text.Json.Serialization.JsonConverter<DateTimeOffset>
4061
{
4162
static readonly DateTimeOffset s_epoch = new(1970, 1, 1, 0, 0, 0, TimeSpan.Zero);
42-
static readonly Regex s_regex = new("^/Date\\(([+-]*\\d+)([+-])(\\d{2})(\\d{2})\\)/$", RegexOptions.CultureInvariant);
63+
static readonly Regex s_regex = new(
64+
"^/Date\\(([+-]*\\d+)([+-])(\\d{2})(\\d{2})\\)/$",
65+
RegexOptions.CultureInvariant);
4366

44-
public override DateTimeOffset Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
67+
public override DateTimeOffset Read(
68+
ref Utf8JsonReader reader,
69+
Type typeToConvert,
70+
JsonSerializerOptions options)
4571
{
4672
string formatted = reader.GetString()!;
4773
Match match = s_regex.Match(formatted);
4874

4975
if (
5076
!match.Success
51-
|| !long.TryParse(match.Groups[1].Value, System.Globalization.NumberStyles.Integer, CultureInfo.InvariantCulture, out long unixTime)
52-
|| !int.TryParse(match.Groups[3].Value, System.Globalization.NumberStyles.Integer, CultureInfo.InvariantCulture, out int hours)
53-
|| !int.TryParse(match.Groups[4].Value, System.Globalization.NumberStyles.Integer, CultureInfo.InvariantCulture, out int minutes))
77+
|| !long.TryParse(match.Groups[1].Value, NumberStyles.Integer, CultureInfo.InvariantCulture, out long unixTime)
78+
|| !int.TryParse(match.Groups[3].Value, NumberStyles.Integer, CultureInfo.InvariantCulture, out int hours)
79+
|| !int.TryParse(match.Groups[4].Value, NumberStyles.Integer, CultureInfo.InvariantCulture, out int minutes))
5480
{
55-
throw new JsonException();
81+
throw new System.Text.Json.JsonException();
5682
}
5783

5884
int sign = match.Groups[2].Value[0] == '+' ? 1 : -1;
@@ -61,12 +87,18 @@ public override DateTimeOffset Read(ref Utf8JsonReader reader, Type typeToConver
6187
return s_epoch.AddMilliseconds(unixTime).ToOffset(utcOffset);
6288
}
6389

64-
public override void Write(Utf8JsonWriter writer, DateTimeOffset value, JsonSerializerOptions options)
90+
public override void Write(
91+
Utf8JsonWriter writer,
92+
DateTimeOffset value,
93+
JsonSerializerOptions options)
6594
{
66-
long unixTime = Convert.ToInt64((value - s_epoch).TotalMilliseconds);
95+
long unixTime = value.ToUnixTimeMilliseconds();
96+
6797
TimeSpan utcOffset = value.Offset;
6898

69-
string formatted = string.Create(CultureInfo.InvariantCulture, $"/Date({unixTime}{(utcOffset >= TimeSpan.Zero ? "+" : "-")}{utcOffset:hhmm})/");
99+
string formatted = string.Create(
100+
CultureInfo.InvariantCulture,
101+
$"/Date({unixTime}{(utcOffset >= TimeSpan.Zero ? "+" : "-")}{utcOffset:hhmm})/");
70102

71103
writer.WriteStringValue(formatted);
72104
}

0 commit comments

Comments
 (0)